Skip to main content

Full text of "Atari ST Disk Drives Inside and Out"

See other formats


Discover the capabilities 
of A " disk drives 




A Data Becker Book 























ST Disk Drives: 

Inside and Out 

Uwe Braun • Stefan Dittrich • Axel Schramm 



A Data Becker Book 
Published by 


Abacus 




mu 





Second Printing, January 1988 
Printed in U.S.A. 

Copyright © 1986 Data Becker GmbH 

MerowingerstraBe 30 
4000 Diisseldorf, West Germany 
Copyright © 1987 Abacus, Inc. 

5370 52nd Street SE 
Grand Rapids MI 49508 

This book is copyrighted. No part of this book may be reproduced, stored 
in a retrieval system, or transmitted in any form or by any means, electronic, 
mechanical, photocopying, recording or otherwise without the prior written 
permission of Abacus, Inc. or Data Becker, GmbH. 

Every effort has been made to insure complete and accurate information 
concerning the material presented in this book. However Abacus, Inc. can 
neither guarantee nor be legally held responsible for any mistakes in printing 
or faulty instructions contained in this book. The authors will always 
appreciate receiving notice of subsequent mistakes. 

Atari, 520ST, 1040ST, TOS, SH204, SF354, SF314 and ST BASIC are 
trademarks or registered trademarks of Atari corporation. GEM and 
GEMDOS are registered trademarks of Digital Research, Inc. GFA BASIC 
is a trademark of Gfa-Systemtechnik. MS-DOS is a registered trademark of 
Microsoft Corp. ST PASCAL Plus is a trademark of CCD. Lattice C is a 
trademark of Metacomco. Pro FORTRAN-77 is a trademark of Prospero 
Software Ltd. 


ISBN 


0 - 916439 - 84-4 



Table of Contents 


1 

Introduction 

1 

2 

Files and programs 

5 

2.1 

File structures and access by high-level languages 

11 

2.1.1 

An overview of GEMDOS functions 

11 

2.2 

File access in BASIC 

14 

2.2.1 

BASIC command overview 

14 

2.2.2 

The sequential file in BASIC 

15 

2.2.3 

The random-access file in BASIC 

16 

2.3 

File handling in Pascal 

19 

2.3.1 

The sequential file in Pascal 

19 

2.3.2 

Random-access files in Pascal 

22 

2.4 

File access in C 

24 

2.4.1 

The sequential file in C 

27 

2.4.2 

The random-access file in C 

29 

2.5 

File handling in FORTRAN 

32 

2.5.1 

The sequential file in FORTRAN 

32 

2.5.2 

The random-access file in FORTRAN 

33 

2.6 

A s’mple database 

35 

3 

Data structures 

43 

3.1 

Diskette format 

45 

3.2 

The boot sector 

47 

3.2.1 

Formatting program 

50 

3.2.2 

The BIOS parameter block 

58 

3.3 

The directory 

65 

3.4 

The FAT 

68 

3.5 

Program construction 

69 

3.5.1 

The program header 

70 

3.5.2 

The relocation table 

72 

3.6 

Hard disk format 

73 

4 

The disk drives 

75 

4.1 

Floppy diskette functions 

77 

4.2.1 

The DMA chip 

79 

4.2.2 

The disk controller 

80 

4.2.2.1 Pinout 

83 

4.2.2.2 Organization 

88 

4.2.2.3 Command description 

96 


m 



4.2.2.4 Status interpretation 126 

4.2.3 The floppy interface 132 

4.3 Connecting the disk drives 133 

5 The SH204 hard disk 137 

5.1 Function and design 138 

5.1.1 The hard disk controller 139 

5.1.1.1 Command structure 141 

5.1.1.2 List of commands 147 

5.1.1.3 HDC tools 153 

5.1.1.4 Partition analyzer 158 

5.2 Connecting the hard disk 167 

5.3 Print the complete directory 168 

6 The RAM disk 177 

6.1 An easy-to-use RAM disk program 181 

6.2 Disk to RAM disk copy 193 

7 Programming a disk monitor 199 

7.1 The TOS functions for disk access 202 

7.2 Listing and operation of the disk editor 210 

7.2.1 The main menu 303 

7.2.2 The TRACK menu 304 

7.2.3 The TRACK with SYNC menu 305 

7.2.4 The SECTOR menu 305 

7.2.5 The CLUSTER menu 306 

7.2.6 The FORMAT menu 307 

7.2.7 The GAP menu 307 

7.2.8 The OPTIONS menu 308 

7.3 Sample use of the disk editor 309 

7.3.1 File Allocation Table 313 

7.3.2 Subdirectories and folders on diskette 315 

7.3.3 Formatting in non-Atari format 316 

7.4 Assembling with different assemblers 318 

8 Machine language utilities for BASIC 319 

8.1 Calling and passing parameters 321 

8.2 Some example programs 323 

8.2.1 B ASIC/TOS interface 323 

8.2.2 Directory reader 325 

8.2.3 Read/write sectors 328 

8.2.4 Any disk format 330 

8.2.5 Searching for data 334 



8.2.7 Reading the date and time 338 

8.3 Programming the FDC in BASIC 341 

8.3.1 The BASIC/FDC interface program 342 

8.3.2 Demo 1—All FDC commands 361 

8.3.3 Demo 2—Copying disks 370 

8.3.4 Demo 3—Creating standard and foreign formats 374 

8.4 Creating BASIC loaders 380 

Appendix 385 

ASCII character set 387 

Index 389 


v 




Chapter One 











Abacus 


Atari ST Disk Drives Inside and Out 


Introduction 


The Atari ST computers are ideal for professional applications with their fast 
16/32-bit processors and their large memory capacities. But equally as 
important as internal memory are the methods of external data storage. The 
floppy disks and hard disks used for storage are very interesting, complex 
storage media which can do much more than you would guess from reading 
the manuals. 

If you want to make optimal use of your ST, it's important to know the 
capabilities of the individual ST components. That is the purpose of this 
book. It first gives you an overview of mass storage methods and describes 
the procedures for writing application programs. Later chapters detail the 
secrets of the Atari floppy disk drives, hard disk drives and even RAM 
disks. 

All of this software and hardware knowledge lets you make the best use of 
these storage media. You can increase the capacity of the disks, develop a 
method of copy protection for your programs, and create a RAM disk to 
meet your own needs. With the help of the example and utility programs 
listed in this book, you'll be able to access your floppy or hard disk much 
faster and much more efficiently. 

In addition, this book and its optional program diskette contain some very 
useful programs. They include a program that prints out a complete 
directory, including the contents of all folders, and one that allows you to 
analyze diskettes or the hard disk. A special feature of this book is a 
complete disk monitor—a program that gives you direct access to disks, 
thereby allowing you to apply all of your new knowledge. You can use this 
disk monitor to recover deleted files, to read "foreign" disk formats and 
much more. 

You will find information in this book that doesn't appear in any ST manual 
or user's guide. These commands or relationships were discovered after 
much work with the ST disk systems. You'll soon find out that the ST disk 
drives can do more than you might have thought. 

We hope that this book helps you answer any questions you may have 
about mass storage on the ST, and that you find this information useful. 

Uwe Braun, Stefan Dittrich, Axel Schramm October, 1986 


3 

















































Chapter Two 















Abacus 


Atari ST Disk Drives Inside and Out 


Files and programs 


The two terms file and program really mean the same thing: Computer data 
stored on some form of external storage medium. It's true that internal 
memory capacity in computers is growing; for example, the Atari 1040 ST 
has 1 megabyte of RAM. However, the computer still must store data that is 
not immediately needed—whether it's a word processing program, the 
population of the city of Chicago, or the price of tea in China—on some 
external medium. Otherwise this data would be lost when the computer's 
power was turned off. 

Magnetic tape, diskettes, hard disks and CD ROMs are used as external 
storage media. With all of the devices that handle these media, the data is 
first encoded on the storage medium, and later read back into the computer's 
memory using electronic circuitry. A group of data stored under one name is 
called a file, regardless of the type of mass storage. 

It is imporant for the user to have at least fundamental knowledge of how 
the computer stores a file, whether it's an address list, a letter, or executable 
program code. For example, a file of stored program code may not have any 
separators between the individual data items. This is different from a file of 
stored text, where separators are often used between individual sentences 
such as carriage returns (i.e., the <Retum> key) and punctuation marks. 

The type of file is indicated by its extension. An extension is three additional 
characters following the name, separated from the name by a period. The 
ST operating system distinguishes between programs and files by means of 
this extension. If you were to change the extension of a program from 
. PRG to . DAT, clicking on this name would only result in this dialog box: 


You can only print or display 
this document. Please click 
on appropriate button to 
do so. 

I Show I I Print I [Cancel | 


7 




Abacus 


Atari ST Disk Drives Inside and Out 


The extensions which the Atari can directly distinguish are: 

. P RG Designates an executable machine language program that can 

run with GEM support. 

. TOS Designates an executable machine language program, but 
GEM will be disabled while it is running. 

• TTP Abbreviation for TOS Takes Parameters; same as .TOS, 
except that before the program is executed a dialog box 
appears, into which you can enter parameters (such as a 
filename for editors). 

. ACC Special machine language programs known as accessories 
are loaded after the computer is turned on. These programs 
remain in memory and can be called as accessories from the 
Desk menu of the Desktop. 

. INF Used by the Desktop for DESKTOP . INF. This file contains 
information about the positions and sizes of the windows, 
the values set for the Control Panel, etc. This file is created 
by selecting Save Desktop from the Options menu. 

Other files such as BASIC programs are equipped with the extension . BAS, 
but this is not vital to the ST operating system. You can load a . TXT file 
into the BASIC interpreter, for instance, if it contains the text of a BASIC 
program. The other extensions are therefore not important, but they can be 
useful for keeping your files in order. 

The actual differences between file types are found in the internal 
construction of the files themselves. Most high-level languages distinguish 
between various file forms, such as those with or without separators 
between strings and numbers, special text modes, etc. We will look first at 
data files which contain only strings and numbers—that is, ASCII data. We 
can use various methods for finding and processing certain data in the file. 

The speed of access to given data on the diskette or hard disk depends 
largely on the "intelligence" of the file management system. 

This can best be shown through a concrete example. Let's say we have a 
file containing the addresses of all of the female inhabitants of Escanaba, 
Michigan. 


8 


Abacus 


Atari ST Disk Drives Inside and Out 


The block of information that contains complete data on an individual, like 
the first and last names, street address, city, state, and zip code, is called a 
record. A single piece of information, like the first name, is a field in the 
record. 


Breen 

Candace 

15 Main Street 

Escanaba Ml 

49829 

555-1213 

Olafsson 

Marian 

13 Mine Street 

Escanaba Ml 

49829 

555-1212 

Psmith 

Laureen 

1 Mime Street 

Escanaba Ml 

49829 

555-1234 

Taber 

Rosalyn 

1562 120 Mi. Rd 

Escanaba Ml 

49829 

555-5555 


A few of the women of Escanaba 


The simplest form of file is a sequential file, in which the data is stored in 
linear sequence, one field after the other. The program which reads this data 
from the file must be able to recognize the end of a record, because a 
separator is used only between the individual fields. 

Generally, every record has a different length. If you want to access the 
10th record, you must read through the file from the 1st record to the 10th 
record. This procedure is acceptable for small files, but what if you had to 
find the address of Willem Zygonze from Wawatosa in a sequential file 
containing every inhabitant of Wisconsin? 

If large quantities of data must be managed, you would generally use 
records of a set length and random-access files. In random-access files, 
each field of a record has a set, predetermined size, such as 12 characters 
for the last name, 10 for the first name, 20 for the street address, 15 for the 
city, 2 for the state, and 5 for the zip code—a total of 64 characters per 
record. 

Now if you want to access the 10th record, you can calculate the start of the 
10th record relative to the start of the file through simple multiplication. You 
then need only start to read at the 10*64=640th byte of the file. At this byte 
you can immediately read your data. This calculation applies only if the 
numbering of the data records starts with 0 and you want record number 10. 


9 



Abacus 


Atari ST Disk Drives Inside and Out 


This trick works only if an arbitrary location in the storage media can be 
directly accessed, which is not possible with audio tape, for example. This 
kind of access is possible with diskettes or a hard disk, because the disks 
themselves are divided into individual, numbered sections called tracks. 

Let's return to our address file example. If we know in which sector the 
first record (record number 0) begins, we can also calculate where the 640th 
byte of the file is located. Let's say that our file starts in sector number 10. 
On the Atari ST, each sector contains 512 bytes. Accordingly, our 10th 
record, or the 640th byte, is found in the 11th sector at byte 640-512, or 
byte 128. 

You don't need to bother with all this arithmetic if you're writing in a 
high-level language. A high-level language is any programming language 
except machine or assembly language. Assembly language programmers 
can also perform these sector calculations using the ST's operating system, 
because the operating system offers such a function (but more about this in 
Chapter 7). 

Building on this simple principle of direct access, there are several forms of 
file organization. For instance, you can sort the entire file according to one 
important field, such as the last name, and then write the sorted names into a 
separate file together with the numbers of the corresponding records. This 
type of file is called an index file. The result is an index-sequential fde 
(index file with sequential access) for which there are some very advanced 
search procedures. An index-sequential file can be used to find and access a 
given record very quickly. 


10 


Abacus 


Atari ST Disk Drives Inside and Out 


2.1 File structures and access by high-level languages 


The operating system of a computer manages the basic operations for file 
handling. The various high-level languages build their file forms around this 
operating system management. As we already mentioned, the Atari ST disk 
operating system GEMDOS supports random-access files. These GEMDOS 
file functions will now be covered briefly, and then discussed in more detail 
as they are used with each high-level language. The programs which follow 
in BASIC, Pascal, C and FORTRAN all have the same effect: They create 
and read a sequential file and a random-access file. 


2.1.1 An overview of GEMDOS functions 


Every file must be given a filename by the user. The maximum length of a 
filename is 11 characters. The first eight characters represent the actual 
filename. The last three characters after the period (which serves as a 
separator) represent the file extension. 

Extensions are necessary for the use of high-level language compilers, i.e., 
programs which convert the language's source text into an executable 
program in machine code. As the complier converts from source text to 
finished program, up to four files are created that have the same name, but 
different extensions. For example, you would write a C sourcecode with an 
editor and call it test 1. c. When you compile and link the program, files 
with the names testl. o (compiled object code) and testl . prg (the 
final linked running program) are created. 

To create a new file, GEMDOS offers the CREATE function (function 
number $3C). The programmer passes the desired filename to the function, 
as well as a special mode word that contains information about the type of 
file. If the file is successfully created (the disk is not write-protected, etc.), 
GEMDOS returns a file number which will be used for all subsequent file 
access. This number is called a handle. 

The CREATE function is called only before the very first access to a file. 
Later access to an existing file can be prepared for by a call to the function 
OPEN ($3D). When calling CREATE, an empty file with the given name is 
created on the current drive, and this file can then be accessed for writing. 


11 


Abacus 


Atari ST Disk Drives Inside and Out 


Many high-level languages incorporate the CREATE function into their 
OPEN commands, so that if a file is opened and it does not already exist, it 
will be created. 

To write to a file, a programmer uses the GEMDOS function WRITE ($40), 
passing it the filename or handle returned by CREATE or OPEN, the 
number of characters to be written, and the characters themselves. Once all 
of the data has been written to the file, it must be closed before that data can 
be accessed. The CLOSE function ($3E) accomplishes this. If the CLOSE 
function is not called, data will probably be lost, or the file's distribution on 
the disk will not be properly marked on the diskette. 

After the file has been created with CREATE, filled with WRITE, and then 
closed again with CLOSE, it can be opened again for reading with the 
OPEN function ($3D). Like CREATE, OPEN is given the filename as well 
as a mode word between 0 and 2. 

A 0 passed as the mode word opens the file for reading only. This means 
that data may only be read from the file. Any attempts to write to the file will 
result in error messages. A mode of 1 opens the file for writing only, and a 
2 allows both reading and writing. The function READ ($3F) is used to 
read data from a file. Like WRITE, this function is given the handle and the 
number of characters to be read. 

File access with READ and WRITE is completely sequential. This means 
that when you open the file with CREATE, the operating system creates a 
pointer to the file, which is always set to zero each time the file is opened. 
This pointer always points to the current position in the file. 

For example, if you write 14 characters in this file, the operating system 
moves this internal pointer 14 positions farther. When the next write access 
occurs, the new characters will be appended to the 14 existing characters. 
You must therefore either specify a given number of characters per field, or 
else a given character must be inserted between fields, so that the end of a 
field can be recognized when the file is read. 

For our address file, which represents a pure text file, we really don't need 
all of the 256 characters which can be represented by 8 bits. All we need are 
the uppercase and lowercase letters, numbers and some punctuation. The 
American Standard Code for Information Interchange (ASCII), the code the 
ST uses to represent characters, has several control characters which mark 
the end of the file or the end of a field, for example. 


12 



Abacus 


Atari ST Disk Drives Inside and Out 


The internal pointer advances by the number of characters read from a file, 
just like when we write to a file. Every character can be read this way, but 
to read the last character in a file, all of the previous characters must be read 
first. The GEMDOS function LSEEK ($42) makes it possible to position 
the internal data pointer to an arbitrary character relative to the start of the 
file, the end of the file, or the current pointer. Again, the parameters must 
include the file handle, the mode word and the desired change to the pointer 
position. 

If the LSEEK mode word has a value of 0, the pointer's position is 
calculated relative to the start of the file. A value of 1 calculates the new 
position of the pointer relative to the current pointer, meaning that negative 
values are also allowed. A value of 2 as the mode word calculates the 
pointer's position relative to the end of the file, and only negative values are 
allowed. With the LSEEK function it is possible to program a 
random-access file using fixed field lengths, such as 12 for the name and 64 
characters for an entire record. This way you can compute the number of 
characters by which the internal data pointer must be moved to get to the 
desired record. 

There are three more GEMDOS functions important for file handling which 
we haven’t yet discussed. 

SETDTA ($1A) sets up a buffer for the two functions SFIRST ($4E) and 
SNEXT ($4F). These latter two functions make it possible to read all the 
files on a diskette from the directory and to determine the lengths of these 
files. 

In the following sections, we'll turn to the individual high-level languages 
and take a closer look at the file handling features for each language. These 
examples are not introductions to the languages themselves, nor do they 
illustrate a complete file management system. They are only intended to 
show concrete examples of how simple it is to create and access a disk file 
in these languages. 

After this semi-theoretical treatment of access techniques, you will find a 
simple but complete database program written in BASIC in Section 2.6. It 
illustrates the practical application of what you will have learned by then. 


13 


Abacus 


Atari ST Disk Drives Inside and Out 


2.2 File access in BASIC 


The ST BASIC language included with the Atari ST provides both 
sequential and random file access. The programs below will run in the GFA 
BASIC® interpreter without alterations. However, the line numbers must 
first be removed with the ST-KILL program included with GFA BASIC®. 


2.2.1 BASIC command overview 


Use the command OPEN to create a disk file. The disk file offers three 
different file options. Here is the command syntax: 

OPEN "mode",#file number,"filename",record length 

The following options, which must be in capital letters, exist for mode: 

"I" = open file for sequential reading (input) 

"O" = open file for sequential writing (output) 

"R" = open file for random access 

#file number is any number between 1 and 15. filename can contain 
a maximum of eight letters followed by a period and three more letters (the 
extension), record length has an effect only when opening a random- 
access file (mode = "R"); it specifies the size of each record in bytes. In 
contrast to the operating system function, you must specify when the file is 
created whether it will use sequential or random access. 

The use of sequential files is severely limited in ST BASIC, because there is 
no way to append data to an existing file. This can only be done with a 
rather roundabout trick. For example, if you have a sequential address file 
with 100 addresses stored, and you want to add an address to the list, you 
would have to read all 100 addresses into memory, add the new address, 
and write the 101 addresses back to disk. 

OPEN " O " erases an existing file with the same name and creates a 
completely new, empty file on the disk. Because of the limited file handling 
capabilities, and the fact that the maximum size of a sequential file is 
dependent on the size of the random access memory (RAM) in the ST itself, 
we will not spend a lot of time on sequential files under ST BASIC. 


14 


Abacus 


Atari ST Disk Drives Inside and Out 


2.2.2 The sequential file in BASIC 


ASCII strings and numbers can be written to a sequential file. Writing 
special characters can cause problems because it is possible that the end of a 
field may not be found, so we'll keep to the ASCII standard. For example, 
this type of file can be opened for writing by the following command: 

OPEN "0",#1,"TEST1.DAT" 

This newly created file is given the filename TEST1. DAT. The WRITE #1 
and PRINT#1 commands handle writing to the file. WRITE outputs a 
comma between the data to be written, while PRINT uses the same 
formatting characters as are used in screen output, such as spaces following 
a comma. 

print# 1 and WRITE#1 have the same syntax: 

PRINT#file number,data[,data, ...] 

WRITE#file number,data[,data, .. .] 

The following command sequence opens the file TEST1. DAT for writing 
and writes data to it: 


10 open "O",#1,"A:TEST1.DAT" 
20 a$ = "Harry" 

30 b$ = "Hirsch" 

40 for i = 1 to 10 
50 write#l,a$ 

60 write#l,b$ 

70 next i 
80 close #1 


This program creates the file TESTl. DAT on the diskette in drive A and 
writes Harry Hirsch to the file ten times. 

The WRITE# function encloses a string in quotation marks and places the 
characters $0D (CR = Carriage Return) and $0A (LF = Line Feed) at the 
end of the output. The character $1A is used by BASIC as the end-of-file 
(EOF) character, and gives the programmer a way of recognizing the end of 
the file. 


15 


Abacus 


Atari ST Disk Drives Inside and Out 


There are two commands in ST BASIC for reading from a sequential file. 
These commands differ only in the way they handle control characters in the 
text to be read: 

The INPUT# function skips preceding spaces, CR's, LF's, and special 
characters. The function starts at the first ASCII character and reads until it 
finds a space, a comma, the end-of-line character (EOL, consisting of $0A 
and $0D [LF and CR]), the EOF character, or a maximum of 255 
characters. The LINE input# function reads all characters from the first 
to the EOL character, or up to 254 characters. Both commands must be 
passed a variable in which to place the characters read, as well as the file 
number. INPUT# 1, a$ reads a string from the file numbered 1 into the 
variable a$. 

The following program fragment opens the file TEST1. DAT created on the 
last page, and reads all strings up to the EOF character. The function 
EOF (f ilenumber ) is used to recognize this. It returns a logical value: 
TRUE if the end of the file was reached, or FALSE if this was not the case. 

10 open "I",#1,"A:TEST1.DAT" 

20 if eof(l) goto 100 
30 input #l,a$ 

40 print a$ 

50 goto 20 
100 close #1 


2.2.3 The random-access file in BASIC 


Random-access file manipulation is implemented much better in ST BASIC 
than sequential access. However, you must learn several commands first, 
because the creation and handling of a random-access file is proportionately 
more complex. 

Opening and creating a random-access file is not much different from 
opening a sequential file. OPEN "R", #1, "TEST2 . DAT", 64 opens the 
file TEST2 . DAT as a random-access file, and declares a record length of 64 
characters for the file. When you later access the file with GET# and PUT#, 
these accesses will always take place in 64-character "segments." 


16 


Abacus 


Atari ST Disk Drives Inside and Out 


The only characters allowed in this type of file are ASCII characters. For 
this reason, all numbers to be written to a random-access file must be 
converted to ASCII codes first. When the file is being read, these codes 
must then be converted back into numbers. There are several BASIC 
functions available for this purpose. 

Generally a random-access file record will contain several fields, e.g., for 
the last name, the first name, etc. This division of available space (in this 
case the 64 characters) is accomplished with the command FIELD #. 

FIELD #1, 10 AS a$, 12 AS b$, 20 AS c$, 15 AS d$, 2 AS e$, 5 AS f$ 

The preceding instruction reserves 10 characters for a$ (first name), 12 for 
b$ (last name), 20 characters for c$ (street address), 15 for d$ (city), 2 
characters for e$ (state), and 5 characters for f$ (zip code). These string 
variables are not accessed directly, but only by way of the functions LSET 
and RSET. LSET a$ = "Harry" transfers the string Harry to the 
string variable a$ and left-justifies it in a$, which can contain 10 
characters. The remaining five characters not used by the word are filled in 
with spaces ($20). 

The command RSET a$ = "Harry" fills the buffer variable right- 
justified; that is, the word Harry will be formatted to the right margin of 
the variable, and the spaces will be placed to the left of the word. 

To write numbers into a random-access file, they must first be converted to 
byte strings. The functions MKD$, MKI$, and MKS$ take care of this: 

MKI$ (number) returns a 2-byte string for integers 

MKS$ (number) returns a 4-byte string for real numbers 

MKD$ (number) returns an 8-byte string for double-precision numbers 

Numbers are converted to ASCII strings by one of these functions before 
they are written to the desired buffer variable and later converted to 
"normal" numbers by another set of functions (CVI, CVS, CVD). 

After the desired buffer variables of the record have been set up with 
FIELD, strings have been placed in the buffer variables with LSET, and 
numbers have been converted by one of the above converters then put in 
place with LSET, the entire record can be written to the file with the PUT 
command. PUT #5, 1 writes the data contained in the buffer variables of 
file number 5 as record number 1. 


17 


Abacus 


Atari ST Disk Drives Inside and Out 


The following BASIC program creates a random-access file with the name 
TEST3.DAT on the disk in drive A, specifies 6 fields for the buffer 
variable, fills the buffer variable with values, and then writes these values to 
the file as records 1 and 2. 

10 open "R",#1,"A:FILE3.DAT,64 

20 field #1/10 as a$,12 as b$,20 as c$,15 as d$,2 as e$,5 as f$ 

30 lset a$= "Harry" 

40 lset b$= "Hirsch" 

60 lset c$= "2222 Oak Dr." 

70 lset d$= "Portland" 

80 lset e$= "OR" 

90 b = 94750 
100 lset f$=mks$(b) 

110 put #1, 1 
120 put #1, 2 
130 close #1 

In line 100, the number 94750 is converted to a 4-byte string by mks$ 
before it is assigned to the buffer variable f $. 

Reading the data in from a random-access file is similar to writing. You 
open the file, define buffer variables, and read a complete record with the 
command GET #1. The individual fields can be accessed directly through 
the corresponding buffer variables. However, numbers must be converted 
back to the normal format, because they are stored in a random-access file 
as strings. The following BASIC program opens the file created above and 
reads all of the records from it, printing the data on the screen. 

10 open "R",#1,"A:FILE3.DAT",64 

20 field #1,10 as a$,12 as b$,20 as c$,15 as d$,2 as e$,5 as f$ 

30 get #1,1 
40 print a$,b$ 

50 print c$,d$,e$ 

60 print cvs(f$) 

70 close 1 

The sizes of the fields may not differ between writing and reading. That 
means that if 13 characters are reserved in the buffer variables for a$ before 
writing, then 13 characters must also be defined for the buffer variable in 
the same position as a$ when the file is read. But the names of the buffer 
variables do not have to be the same when reading as when writing. 


18 


Abacus 


Atari ST Disk Drives Inside and Out 


2.3 File handling in Pascal 

This description of file functions in Pascal is based on the ST PASCAL 
Plus® compiler by CCD. This compiler is a veiy good implementation of 
Pascal on the Atari ST—it goes far beyond the Pascal standard. ST 
PASCAL Plus supports both sequential and random-access files. 

The data type file of or the predefined type text (which can be used 
only for sequential files and which corresponds to the type packed 
array of char) can be used. For example: 

var dat: file of integer 

This instruction declares a file which will hold integer numbers and the 
corresponding pointer as the variable dat, which points to the element 
currently being accessed in the file. 


2.3.1 The sequential file in Pascal 


After declaring a file variable of type file of , a new file will be created 
by the function rewrite (internal filename, 'external 
name ' ) , which is similar to the BASIC command OPEN "O". This 
command will create a file with the given filename and assign it an external 
name. The filename must be declared as a variable of type file of in the 
declaration section. The file can be accessed via the filename or the buffer 
variable defined by rewrite (same name with an appended A ). 

internal filename represents the file within the Pascal program and 
the external name in single quotes represents the same file on the mass 
storage medium (disk file). For example, if you declare the file dat with: 

var dat: file of integer; 

and open it with rewrite (dat, 'a : sfile .dat ' ) for sequential 
writing, the buffer variable dat A will be defined at the same time which can 
accept an integer, and which points to the first element in the file. In 
addition, the file sfile . dat will be created on the disk in drive A and 
opened for writing. All subsequent input and output refers to this disk file. 


19 




Abacus 


Atari ST Disk Drives Inside and Out 


To read an existing file, it must be opened with reset (internal 
filename, 'external name '). This command opens an existing 
file for reading and transfers the first record into the buffer variable. If an 
attempt is made to open a nonexistent file, eof ( ) will be TRUE. 

The function eof (internal filename) returns a value of type 
boolean (TRUE or FALSE). TRUE is returned if the file pointer points to 
the end of the file, eol (f ile variable) is also a function of type 
boolean, but it can only be used on files of type packed array of 
char or text and returns TRUE when the end of the line is reached. 

Access to the data in the file is made via put (internal filename) 
for write access and get (internal filename) for read access. 

put (dat ) writes the value of the buffer variable dat A in the file. The 
buffer variable represents a pointer to the file, which is set to zero by 
rewrite or reset and is incremented by one with get or put upon 
each access. This sets the pointer to the next element in the file. After 
opening the file for reading with reset (dat, 'name '), the first file 
element is transferred to the buffer variable dat A . A subsequent 
get (dat ) increments the file pointer by one and transfers the value to 
which the pointer points to the buffer variable dat A . The function 
eof (file variable) is used to recognize the end of the file. This 
function returns a value of type boolean. In the example, we must test for 
the end of the file before the access with get, because get increments the 
file pointer and tries to read the next file element into the buffer variable. 
With files of type text it is also possible to recognize the end of the line 
with the function eol (file variable) , which returns a value of type 
boolean. 

All available data types in Pascal, including records, can serve as possible 
file elements. After a file has been opened with rewrite, the buffer 
variable can be assigned a value, which can then be written to the file with 
put. For pure text files, those of type packed file of char (text), 
the command sequence necessary for writing a file element, assigning a 
value to the buffer variable through dat A : = value ; and writing this 
value to the file with put (dat) ; can be abbreviated to the command 
write (dat, value) ;. Similar to this, the command read (dat, 
value) reads from a text file and replaces the commands value : = 
dat A and get (dat ) . 


20 




Abacus 


Atari ST Disk Drives Inside and Out 


The following Pascal program creates a file on the diskette in drive A and 
writes 20 strings to it. In CCD Pascal, string [20] defines a variable of 
type packed array of char which can hold 21 characters. The 
Pascal compiler stores the length of each string at the start of each string, 
inserting it in the null character. 

(* Writing a sequential file in Pascal. D.B. 9.86 *) 


program sfile ; 


var 


datl 

tl,t2 

i 


file of string[20] ; 
string[20] ; 
integer ; 


begin 

rewrite (datl, 'a:seqfile.dat' ); 
tl := 'Harry'; 
t2 := 'Hirsch'; 

for i:= 1 to 10 do 
begin 

datl A := tl; 
put (datl); 
datl A := t2; 
put (datl); 
end; (* for loop *) 


end. (* program *) 

If you look at the created file seqfile.dat with the disk monitor 
presented in Chapter 7, you can clearly see the organization of a sequential 
Pascal file with string variables (21 characters per string, string length at the 
start of the string). The following program reads the file created by the 
program above: 


(* Reading a sequential file in Pascal. U.B. 9.86 *) 
program readfile ; 


var 


dat 1 
tl, t2 
i 


file of string [20] ; 
string[20] ; 
integer ; 


begin 

writeln (' Read file '); 
reset (datl,'a:seqfile.dat'); 


21 




Abacus 


Atari ST Disk Drives Inside and Out 


while not eof(datl) do 
begin 

tl := datl*; 
get (datl); 
writeln (tl); 
end; (* while loop *) 
writeln; 

writeln (' Press the Return key '); 
readln (t2); 

end. (* program *) 

After opening the file with reset (datl, ' a : seqf ile . dat ' ), the 
first file element will be assigned to the buffer variable dat 1 A , so that the 
buffer variable can process a variable immediately after opening the file. 
This variable must naturally be the same type as the buffer variable defined 
along with the declaration of the file variable, or errors can occur. 
Moreover, no attempt may be made to read data beyond the end of the file. 
The function eof (datl) checks to see if the end of the file has been 
reached. The read loop will be exited in this case. 

As in BASIC, there is no way to append data to an existing sequential file in 
Pascal. If you want to expand an existing file, you will have to read in the 
entire file, add the new file elements and write it all out to a new file. 

Creation of and access to files of other data types (file of integer, 
file of real) is done in the same way as the examples given here. 


2.3.2 Random-access files in Pascal 


Creating random-access files and opening them for reading uses the same 
commands that are used for sequential files (rewrite, reset). Even the 
access to individual pieces of data is similar. There is only one additional 
parameter for get and put: the number of the record which is to be read or 
written. The numbering of records starts with 0, whereby all records 
between 0 and the largest number must first be created. For example, if the 
last record has the number 8, then record number 10 cannot be created until 
record number 9 has been written. The short example program below 
demonstrates the flexibility of this file type. The program creates a small 
address file to which the same address is written 10 times. 


22 




Abacus 


Atari ST Disk Drives Inside and Out 


(* Random-access file writing in Pascal. U.B. 9.86 *) 
program ranfile ; 

type addr = 
record 

fname : string[10]; 
lname : string[12]; 
street : string[20]; 
city : string[15]; 
state : string [2]; 
zip : string[5]; 
end; (* record *) 


var 


datl 

tl,t2 

i 


file of addr; 

addr; 

integer; 


begin 

rewrite(datl,'a:randoml.dat'); 

tl. fname := 'Harry'; 

tl.lname := 'Hirsch'; 

tl. street := '2222 Oak Dr.'; 

tl.city ;= 'Portland'; 

tl.state := 'OR'; 

tl.zip := '94750'; 

for i:= 0 to 9 do 

begin 

datl"' := tl; 
put (dat1,i); 
end; (* for loop *) 


end. (* program *) 

In CCD Pascal, the command dat 1 A : = 11; passes the entire address 
record (with first name, last name, etc.) to the buffer variable, which is then 
written to the file as record number 1 with put (dat 1, i). 

As you can see, the number of characters in a string is stored before the first 
character of the string, simple integers are stored as 2-byte hexadecimal 
numbers. Pascal uses the number $F5 as the end-of-file character. 


23 






Abacus 


Atari ST Disk Drives Inside and Out 


2.4 File access in C 


The C language can be considered the native language of the Atari ST. 
Large parts of the TOS are written in this language. Therefore it's not 
surprising to find the GEMDOS functions described in the introduction to 
this chapter in the language description of C, although in a modified form. 

From the user's point of view, C is an incomplete language. That's because 
many functions, including the functions for file management, are omitted 
from the C language, and the user has to design them himself. However, all 
C compilers come with the standard I/O library—the #include file 
stdio . h as described by C authors Brian W. Kemighan and Dennis M. 
Ritchie. To use the file functions, this file must be integrated into the C 
program at its beginning with the command #include "stdio. h". 

One of the problems for someone learning C on the Atari ST, other than the 
chaotic appearance of the operators and abbreviations (&, !=, I | , 

etc.), is the initial version of the Digital Research C compiler for the ST. An 
inexperienced C programmer can never be sure whether a given problem or 
error lies was caused by his program or by the Digital Research compiler 
itself. For this reason, all of the C programs presented here have been 
compiled with the Lattice C® compiler from Metacomco. It shouldn't be 
difficult to adapt the program to other C compilers, because only the 
standard functions from the stdio. h library are used. 

Communication with files in C is accomplished by a data structure of type 
FILE, which is defined in the stdio . h library along with the functions 
for accessing this data structure. Here is an overview of the individual 
access functions with the data types of their parameters: 

pointer = fopen(name, mode) 

FILE *fopen() 

FILE *pointer 
char *name 
char *mode 


24 




Abacus 


Atari ST Disk Drives Inside and Out 


Here are the possible mode words: 

"w" : create a file and open for writing 
"a" : open an existing file for appending data 
"r" : open an existing file for reading data 

In addition to these, there are other mode words which have different 
functions depending on the compiler used, but they are not of importance to 
us in this case. 

The above function opens a file with subsequent access dependent upon the 
mode word. If an error occurs and the file cannot be opened, the pointer 
will equal NULL, or else it will contain the pointer to the file. 

code = fclose(pointer) 

int code 
FILE *pointer 

This closes the file to which pointer points. 

fprintf(pointer, format, arguments) 

FILE *pointer 
char *format 
char *arguments 

This function writes multiple arguments, separated by commas, to the file 
with the format described by format. The format parameters correspond 
to the those of the normal print f function. 

code = fscanf(pointer, format, chpointer) 

FILE *pointer 
char *format 
char *chpointer 
int code 

This function reads strings from the file specified by pointer in the format 
specified by format into the variable chpointer. The format options are 
identical to those of the scanf function. 


25 





Abacus 


Atari ST Disk Drives Inside and Out 


code = fputs(buffer, pointer) 

FILE *pointer 
char *buffer 
int code 

This function writes a string to which buffer points, to the file to which 
pointer points. If an error occurs, code will equal EOF. The zero byte 
which terminates a C string is not written, but the string is terminated with a 
NEWLINE character. 

code = fgets(buffer, number, pointer) 

FILE *pointer 
char *chpoint 
char ^buffer 
int number 
int code 

This code reads number characters from the file to which pointer points 
into the buffer to which buffer points. It will stop reading when the 
end-of-line character (EOL) is encountered. A zero-byte will be appended to 
the string and the pointer to the buffer will be returned in chpoint. After 
an error-free access, chpoint points to buffer, otherwise chpoint 
will contain a 0, which is expressed as null in C. 

code = fputc(chr, pointer) 

FILE *pointer 
char chr 
int code 

A single character, contained in chr, is written into the file to which 
pointer points. After an error, code = EOF, otherwise code contains 
the character written. 

code = fgetc(pointer) 

FILE *pointer 
int code 


26 




Abacus 


Atari ST Disk Drives Inside and Out 


The above function reads a single character from the file to which pointer 
points. The code of the character read will be returned in code, EOF if the 
end of the file was reached. 

code = fseek(pointer, position, mode) 

FILE *pointer 
long position 
int mode 
int code 

Sets the file pointer of the file to which pointer points to a new value. 
The mode parameter specifies the new position of the pointer and can have 
the following values: 

0 : set new position relative to the start of the file 

1 : set new position relative to the current position 

2 : set new position relative to the end of the file 


2.4.1 The sequential file in C 

The following C program opens the file SEQFILE . DAT for writing and 
writes Harry Hirsch into this file 10 times. 

/* Writing to a sequential file in C. U.B. 9.86 */ 

#include <math.h> 

#include <stdio.h> 

main() 

{ 

int i, k; 

FILE *datl, *fopen(); 

char *tl = "Harry"; 
char *t2 = "Hirsch"; 

datl = fopen("a:seqfile.dat","w"); 

for (k=l; kcll; k++) 

{ 

fprintf(datl,"%13s",tl); 


27 




Abacus 


Atari ST Disk Drives Inside and Out 


fprintf(datl,"%13s",t2) ; 

} /* end of the for loop */ 

i = fclose(datl); 
printf("Press a key\n"); 

getchar(); 

} /* End main */ 

The following program reads the file just written and displays the contents 
of the entire file on the screen: 

/* Reading a sequential file in C. U.B. 9.86 */ 

♦include <stdio.h> 

main () 

{ 

int i, k; 

FILE *datl, *fopen(); 

char space[14]; 
char *p; 

datl = fopen("a:seqfile.dat","r"); 

while (p = fgets(space,14,datl) != NULL) 

{ 

printf("%s\n",space); 

) /* End of while loop */ 

i = fclose(datl); 
printf("\n\n"); 

printf("Press key"); 

getchar(); 

) /* End main */ 


28 




Abacus 


Atari ST Disk Drives Inside and Out 


2.4.2 The random-access file in C 


The function f seek (), which allows positioning of the file pointer to a 
specific character within the file, is required to make random-access files 
possible in C. Each field receives a set length as a result of the formatted 
output to the file with fprintf (). As a result, each complete record (such 
as an address) also has a precise, set length (which, in our case, is 64 
characters). To read the 10th record, you need only multiply the length of a 
record with the number of the desired record, set the file pointer to the 
computed value, and the desired record can be processed. In C the 
numbering of the records starts with zero. 


/* Writing a random-access file in C. U.B. 9.86 */ 

tinclude <math.h> 

#include <stdio.h> 

char *fname = "Harry"; 

char *lname = "Hirsch"; 

char *street = "2222 Oak Dr."; 

char *city = "Portland"; 

char *state = "OR"; 

int zip = 94750; 

main () 

{ 

int i, k; 

FILE *datl, *fopen(); 

datl = fopen("A:random2.dat","w"); 

for (k=l; k<ll; k++) 

{ 

fprintf(datl,"%10s",fname) ; 
fprintf(datl,"%12s", lname) ; 
fprintf(dat1,"%2 Os",street); 
fprintf(datl,"%15s", city) ; 
fprintf(datl,"%2s",state) ; 
fprintf(datl,"%5d",zip) ; 

} /* End for loop */ 


29 




Abacus 


Atari ST Disk Drives Inside and Out 


i = fclose(datl); 

printf("Press a key\n"); 
getchar () ; 

} /* End main */ 

The following program reads all of the data from the file and displays it on 
the screen, including the record number and relative position within the file: 

/* Reading a random-access file in C. U.B. 9.86 */ 

♦include <math.h> 

♦include <stdio.h> 

♦define LENGTH 64L 

main () 

{ 

int k, il, i; 

FILE *datl, *fopen(); 
long pos; 

char space[80], *p; 

datl = fopen("a:random2.dat","r"); 
k = 0; 

pos = k*LENGTH; 

while ((i = fgetc(datl)) != EOF) 

{ 

i = fseek(datl,pos,0); 

printf(" Record number = %8d\n",k); 

printf (" Byte pos. in file = %8d\n",pos); 
printf ("\n"); 

p = fgets(space,11,datl); 

printf (" First name = %s\n",space); 

p = fgets(space,13,datl); 

printf(" Last name = %s\n",space); 


30 




Abacus 


Atari ST Disk Drives Inside and Out 


p = fgets(space,21,datl); 
printfC Street = %s\n",space); 

p = fgets(space,16,datl); 
printfC City = %s\n", space) ; 

p = fgets(space,3,datl); 
printfC State = %s\n", space) ; 

p = fgets(space,5,datl); 

il = atoi(space); 

printfC Zip code = %8d\n",il); 

k+=l; 

pos=k*LENGTH; 

printf ("****************************\ n \ n ii) . 

} /* End WHILE loop */ 

i = fclose(datl); 
printf("\n\n"); 

printf("Press a key\n"); 

getchar(); 

) /* End main */ 


31 




Abacus 


Atari ST Disk Drives Inside and Out 


2.5 File handling in FORTRAN 


All of the examples using FORTRAN here refer to the Pro FORTRAN-77® 
compiler from Prospero. Like CCD Pascal, this FORTRAN allows both 
sequential and random-access files. The Atari implementation is quite good, 
and all language definitions meet FORTRAN-77 standards. In comparing 
the speed of compiled code, at least in terms of mathematical computations, 
this compiler is substantially faster than the C and Pascal compilers. 


2.5.1 The sequential file in FORTRAN 


The OPEN function is used to create a sequential file as well as open a file. 
OPEN (5, FILE = ' a: fdatl. dat ') opens a file on access unit 5 
with the name "f dat 1 . dat" on drive A. This file will be created if it does 
not already exist. 

The normal I/O command WRITE, with optional parameters, can be used to 
write to this file. WRITE (5) "Harry" writes to file unit 5. The WRITE 
command also supports the standard FORTRAN formatting options, 
although we do not have the space to discuss them here. 

Here is the FORTRAN version of our example program which creates a 
sequential file and writes the name Harry Hirsch into the file 10 times: 

PROGRAM SEQ1 

CHARACTER*13 LNAME, FNAME 

FNAME = "Harry" 

LNAME = "Hirsch" 

OPEN (2, FILE='A:FSEQ1.DAT', FORM='UNFORMATTED') 

DO 100 N = 1,10 
WRITE (2) FNAME 
WRITE (2) LNAME 
100 CONTINUE 
CLOSE (2) 

END 


32 




Abacus 


Atari ST Disk Drives Inside and Out 


The following program reads the data from the sequential file: 

PROGRAM SEQ2 
CHARACTER*2 T1 
CHARACTER*13 TEXT 

OPEN (2, FILE='A:FSEQ1.DAT 1 , FORM='UNFORMATTED 1 ,STATUS='OLD') 

100 CONTINUE 

READ (2,END=200) TEXT 
WRITE (*,*) TEXT 
GOTO 100 

200 CONTINUE 
CLOSE (2) 

END 


2.5.2 The random-access file in FORTRAN 


Back to our standard random-access file program, this time in FORTRAN: 

C Write a random-access file in FORTRAN. U.B. 9.86 

PROGRAM RAND1 
INTEGER*4 ZIP 

CHARACTER*10 FNAME 
CHARACTER*12 LNAME 
CHARACTER*20 STREET 
CHARACTER*15 CITY 
CHARACTER*2 STATE 

FNAME = 'Harry' 

LNAME = 'Hirsch' 

STREET = '2222 Oak Dr.' 

CITY = 'Portland' 

ZIP = 94750 

OPEN (2, FILE = 'A:\FRAND1.DAT', REC1 = 64, ACCESS = 'DIRECT') 

DO 100 N = 1,10 

WRITE (2,REC = N) FNAME, LNAME, STREET, CITY, ZIP 
100 CONTINUE 
CLOSE (2) 

END 


33 


Abacus 


Atari ST Disk Drives Inside and Out 


The next program reads the data from the file: 

C Read a random-access in FORTRAN. U.B. 9.86 

PROGRAM RAND1 
INTEGER*4 ZIP, STAT 

CHARACTER*10 FNAME 
CHARACTER*12 LNAME 
CHARACTER*20 STREET 
CHARACTER*15 CITY 
CHARACTER*2 STATE 

OPEN (2, FILE = 'A:\FRAND1.DAT', REC1 = 64, ACCESS = 'DIRECT', 

- STATUS = ’OLD) 

N=1 

10 CONTINUE 

READ (2, REC = N, IOSTAT = STAT) FNAME, LNAME, STREE, CITY, ZIP 


IF (STAT 

.EQ. 

0) THEN 




WRITE 

(*, 

*) ' 

Record 

number: ' 

, n 

WRITE 

(*, 

*) 





WRITE 

(*, 

*) ' 

First name 

— 1 

r 

FNAME 

WRITE 

<*, 

*) ' 

Last name 

— l 

r 

LNAME 

WRITE 

<*, 

*) ' 

Street 


— 1 

r 

STREET 

WRITE 

(*, 

*) 

City 


— i 

CITY 

WRITE 

(*, 

• (a. 

i 6) ') ’ 

Zip 

code 

— 1 

r 

WRITE 

(*, 

*) 





WRITE 

<*, 

*) 






N = N+l 
GOTO 10 

ELSE 

WRITE (*,*) 

WRITE (*,*) 

WRITE (*,*) ' Press a key' 

CLOSE (2) 

END IF 
END 


34 





Abacus 


Atari ST Disk Drives Inside and Out 


2.6 A simple database 


After all of this theory, we want to demonstrate some practical data/file 
management techniques with a simple database program. This program 
probably isn't the best thing to use for warehouse inventory, but it will 
work well for listing telephone numbers or managing your record 
collection. 

The program is written in ST BASIC, which is included with the Atari ST. 

When creating such a program, you should consider what a database 
program should be able to do. This program has some of the most important 
functions: 

• Create a new database 

• Input new data or correct old entries 

• Load an existing database into memory 

• Output data on the screen or printer 

• Search for given keywords 

• Sort data according to a field 

• End the program 

These functions are accessible from a simple menu displayed on the screen. 
To select a function, simply enter the function number and press <Retum>. 

Before we take a closer look at the individual functions, it would be a good 
idea to enter the program first: 

10 i*** Mini-Database S.D. *** 

20 dim d$(5),i$(5),1(5),p$(500) ,r(500) 

30 for i=l to 500: r(i)=i: next i 

40 for i=l to 5: d$(i)=space$(100) 

50 i$(i)="" : next i 

60 start: 

70 fullw 2: clearw 2: gotoxy 0,0 

80 ? "**** Mini-database from ST Drive Book **** 

90 ? d;" Data sets available in file ";f$ 

100 for i=l to 5 

110 gotoxy 28,1+i: ?i;") ";i$(i) 

120 next i 

130 if so then gotoxy 21,1+so: ?">" 

140 gotoxy 0,6 

150 ?: ? "1) Create a database" 


35 




Abacus 


Atari ST Disk Drives Inside and Out 


160 

7 

" 2 ) 

Input the data" 

170 

7 

"3) 

Load the data" 

180 

7 

"4) 

Sort the data" 

190 

7 

"5) 

Search" 

200 

7 

" 6 ) 

Output the data" 

210 

7 

"7) 

End" 

220 

? 

input "Your choice ";w 


230 on w gosub create,enter,lading,sort,search,output,ende 

240 goto start 

250 

260 '** create the database ** 

270 create: 

280 ? " ** Database create : 500 items with 5 fields free **" 

290 sum=0 

300 ?: for i=l to 5 

310 ? i;". Field name,Length 

320 input i$(i),l(i) 

330 sum=sum+l(i) 

340 next i 

350 ?: input "OK ";o$ 

360 if o$="n" or o$="N" then create 
370 gosub getfn 

380 open "0",#l,fi$ 

390 for i=l to 5 

400 printtl,i$(i) 

410 printtl,1(i) 

420 d$(i)=space$(1(i)) 

430 next i 

440 close #1 

450 open "R",#1,fd$,sum 

460 field #1, 1(1) as d$(l), 1(2) as d$(2), 1(3) as d$<3), 1(4) 
480 return 

490 ' 

500 '** Enter the data ** 

510 enter: 

520 clearw 2: gotoxy 0,0: ? " *** Data entry *** 

530 ? d;" Data sets available" 

540 gotoxy 0,3:? "Number ";d+l 

550 gotoxy 0,4: input "Number ";d$ 

560 if len(d$)>0 then dl=val(d$) else dl=d+l 
570 if dl=0 then return 

580 if dl>d+l then enter 

590 if dl<d+l then gotoxy 0,5: o$="b": gosub outputl 

600 for i=l to 5 

610 gotoxy 0 ,4+i 

620 ?i$(i);: gotoxy 20 ,4+i 

630 input d$ 


36 


Abacus 


Atari ST Disk Drives Inside and Out 


640 if len(d$)>0 then Iset d$(i)=d$ 

650 next i 

660 ?: input "OK (y/n) ";o$ 

670 if o$="n" or o$="N" then enter 
680 if dl=d+l then d=d+l 
690 put #l,r(dl) 

700 goto enter 
710 

720 '** Database load ** 

730 lading: 

740 gosub getfn 
750 close #1 
760 sum=0 
770 open "I",#l,fi$ 

780 for i=l to 5 
790 inputtl,i$(i) 

800 inputtl,1(i) 

810 sum=sum+l(i) 

820 d$(i)=space$(1(i)) 

830 next i 

840 close #1 

850 open "R",#1,fd$,sum 

860 field #1, 1(1) as d$(l), 1(2) as d$(2), 1(3) as d$(3), 1 
d$ (4) , 1(5) as d$ (5) 

870 d=0 

880 while not eof(l) 

890 d=d+l 
900 get #l,d 
910 wend 
920 return 
930 ' 

940 1 ** Data output ** 

950 output: 

960 if d=0 then ? "No data available !": goto waitkey 
970 ? " ** Data output **" 

980 input "S)creen or P)rinter ";o$ 

990 for dl=l to d 
1000 gosub outputl 

1010 if o$="p" or o$="P" then lprint else ? 

1020 next dl 
1030 waitkey: 

1040 gotoxy 30,16: input "-Press 'Return'-",w$ 

1050 return 
1060 outputl: 

1070 get #l,r(dl) 

1080 for j=l to 5 

1090 if o$="p" or o$="P" then lprint i$(j),d$(j) else ? i$(j) 


(4) as 


, d $ ( j) 


37 


Abacus 


Atari ST Disk Drives Inside and Out 


1100 next j 
1110 return 
1120 ' 

1130 '** Search ** 

1140 search: 

1150 if d=0 then ? "No data available!": goto waitkey 
1160 ?: input "Field number,Text ";f,t$ 

1170 for dl=l to d 
1180 get #l,dl 

1190 if instr(d$(f),t$) then gosub outputl: ? 

1200 next dl 
1210 goto waitkey 
1220 ' 

1230 '** Sort ** 

1240 sort: 

1250 if d=0 then ? "No data available!": goto waitkey 

1260 ?: input " Which field to sort on ";so 

1270 if so=0 or so>5 then return 

1280 for i=l to d 

1290 get #l,i 

1300 p$(i)=d$(so) 

1310 next i 
1320 for i=l to d 
1330 for j=i to d 

1340 if p$(r(i))>p$(r(j)) then swap r(i),r(j) 

1350 next j 
1360 next i 
1370 return 
1380 ' 

1390 '** End ** 

1400 ende: 

1410 close #1 

1420 ?: ? "**** End Program ! ****" 

1430 end 
1440 ' 

1450 '** subroutines ** 

1460 getfn: 

1470 ?: input "Filename ";f$ 

1480 fi$=f$+".idx" 

1490 fd$=f$+".dat" 

1500 return 


38 


Abacus 


Atari ST Disk Drives Inside and Out 


Now we'll discuss the individual functions: 

1) Creating a database 

After calling this function, you will be asked five times to enter two 
parameters: field name and field length. Here you enter the name of the 
field, followed by a comma and the maximum length of this entry in 
characters. For an address database, this might look like this: 

First name,10 
Last name,15 
Street address,25 
City,16 
Telephone,13 

Once you have entered these, you will be asked if the information is correct 
(OK?). If it is, enter Y here (the program accepts upper or lower case 
lettering). 

You will then be asked for the filename under which the database will be 
stored on the disk. The drive may be included along with the name, as in 
A: TEST. You may not enter an extension (like . DAT) because the program 
creates two files with the same name but different extensions. After the 
program is run you'll find one file with the extension . IDX. This file 
contains the names and lengths of the data fields, as well as one with the 
extension . DAT, which contains the records themselves. 

Once the data items are entered and stored on the disk, the main menu will 
be displayed again. 

2) Enter data 

After selecting this function, you will be told how many records currently 
exist, and you will be asked to enter the name of the record to enter or 
modify. The number of the next available record is supplied behind the 
question mark, so you just have to press <Retum> to enter a new record. 

If you want to change a record, enter its number and you will be shown the 
old contents of the record as well as a question mark requesting that you 
enter new data. If you want to keep the old contents of a data field, just 
press <Retum>. 


39 


Abacus 


Atari ST Disk Drives Inside and Out 


Additional data is entered in the same way. If you want to stop entering 
data, enter 0 for the record number. 

3) Load a database 

Here you are asked for the name of the database. Again, you can enter only 
the drive and the filename without an extension. The main menu will be 
displayed again once the database is loaded, and the menu will list the name 
of the file, the number of entries in it and the field names. 

4) Sorting the data 

If you want to sort the records based on a specific field, choose this 
function. You will be asked for the number of the field by which the records 
are to be sorted. For example, you can use this to sort your address list by 
name, print it out, and then sort by zip code and print it out again. 

The sort function does not contain any output function. A > character will 
be placed in front of the field name with which you last sorted the file. 

5) Search 

This function asks you to enter a field number and a search string. For 
example, if you want to output all the addresses in Wawatosa, you would 
enter "4, Wawatosa" in the previous example. All records whose city field 
(field number 4) contains the string Wawatosa will be displayed. You can 
also enter just part of search string. 

6) Output data 

This function allows you to output all records to the screen or printer. 
Answering the question regarding the destination of the output with p 
sends it to the printer, while all other input sends it to the screen. 

The records are output in the order they were entered, unless you first call 
the sort function. 

7) End 

The opened data channel is closed (CLOSE # 1 ) and the program ends. 


40 


Abacus 


Atari ST Disk Drives Inside and Out 


The program uses both sequential and random-access files. The field names 
and lengths of the fields are stored sequentially (name . IDX), and the 
records themselves are placed in a random-access file (name . DAT). For 
small databases and with the large memory capacity of the Atari ST, you 
could also store all data sequentially in an appropriate string array and 
manage it directly in memory. However, this takes more time to load, and 
works only if everything is saved again after it is accessed and edited. 


41 



Chapter Three 






Abacus 


Atari ST Disk Drives Inside and Out 


Data structures 


Writing to disk is basically a matter of taking a large set of data and placing 
it on diskette. It sounds simple enough, but when we look at the procedures 
more closely, certain areas present some difficulties. 

First of all, the diskette must be organized in such a way that the data can be 
found again. Some preparations are necessary for this. You don't have to 
bother much with the details, but the operating system and the computer and 
disk drives must execute many complex steps. 

A diskette must be formatted before it can be used. During formatting, the 
surface of the diskette is divided into individual sectors whose positions are 
determined by the format used. 

The computer must be able to recognize this format, because it can work 
with different formats. The number of sides of the diskette used is as 
important as the number of sectors and their length. This information is 
contained in the boot sector, which we'll examine in detail. 

The sectors used for every file or program stored on the diskette must be 
assigned and marked. This information is stored in the File Allocation Table 
(FAT) of the disk directory. This will be discussed in the next chapter. 


3.1 Diskette format 


As we explained before, when a diskette is formatted it is divided into 
individual sections. The diskette is first divided into tracks. These tracks are 
concentric rings on the diskette and are numbered from the outside in. There 
are 80 such tracks on a normally formatted diskette, numbered from 0 to 79. 
It is possible to format up to 82 tracks, but the data security decreases 
toward the center because of the reduced available space. For this reason 
tracks 80 to 82 are not used. They can be used if formatted appropriately. 

The individual tracks are in turn divided into sectors. The sectors represent 
segments of the track rings. These sectors are combined into clusters, 
usually two sectors per cluster. Clusters are not very significant, so we will 
ignore them and discuss only sectors. 


45 



Abacus 


Atari ST Disk Drives Inside and Out 


In the normal diskette format there are 9 sectors on every track, and each 
sector comprises 512 bytes. This results in a storage capacity of 
80*9*512=368640 bytes on a single-sided disk. 


However, 368640 is not the actual number of bytes stored on the diskette. 
Additional information is placed on each track and each sector during 
formatting. This data is required by the disk controller , the chip that controls 
the disk drive in the Atari ST. The disk controller uses the information to 
find the proper sector in the track. Let's look at the complete construction of 
a normal track. 


Number 

Bytes 

60 

$4E00 

per sector: 

12 

$00 

3 

$F5 

1 

$FE 

1 

track# 

1 

side # 

1 

sector # 

1 

$02 

1 

$F7 

22 

$4E 

12 

$00 

3 

$F5 

1 

$FB 

512 

Data 

1 

$F7 

40 

$4E 


end of track: 

1401 $4E 


Comments 

Start of track 


will be written as $A1 
ID address mark 
track number 0 to 79 
side number 0 or 1 
sector number 1 to 9 
*$100=512 bytes per sector 
CRC checksum (will be 2 bytes) 
filler bytes 

tt 

become $A1 

marker (data address mark) 
the actual sector data 
write CRC checksum 
filler bytes 


filler bytes 


If you add all of these bytes together, you get 6969 bytes per track, which 
corresponds to an unformatted diskette capacity of 557520 bytes. 
Unfortunately, this capacity cannot all be used for data, or else the controller 
wouldn't be able to find the data again (how would it recognize the start and 
end of a sector?). 


46 



Abacus 


Atari ST Disk Drives Inside and Out 


However, it is possible to use the last 1401 bytes of each track for an 
additional sector. This would increase the usable diskette capacity to 409600 
bytes. If we also use the three additional tracks (80 to 82), the total storage 
space increases to 424960 bytes. But as we said, the security of the data 
decreases. 

We'll need a short program to create this custom disk format. Before we 
take a look at such a program, we must take a closer look at the individual 
steps that comprise the formatting process. It isn't enough just to format the 
tracks. The parameters used, like the number of tracks and sectors, must be 
written on the diskette or the ST will not be able to determine how the 
diskette is formatted. This is where the boot sector comes in. 


3.2 The boot sector 


The boot sector always lies at the very beginning of a diskette or hard disk: 
track 0, side 0, sector 1 of a diskette, or sector 0 of a hard disk. Like all the 
other sectors, the boot sector is 512 bytes long and is checked by the 
operating system every time the diskette is changed. 

In addition, the boot sector plays a decisive role in booting the diskette. 
Booting refers to loading the operating system from diskette after the 
computer is turned on. First the boot sector of the diskette in drive A is 
loaded and checked to see if the diskette contains an operating system. The 
boot sector also contains additional information. 

The boot sector contains the serial number of the diskette, a parameter block 
for the BIOS of the computer, and possibly a boot program with boot 
parameters. If this program is present, the sum of all the bytes in the sector 
(checksum) must yield the "magic number" $1234. If the checksum equals 
$1234, the program at the start of the sector, which usually contains a BRA 
(branch always) command, is executed. The program must be written so 
that it can run at any memory location. 

Normally, a boot sector does not contain such a boot program. More 
important are the various parameters which are found in the sector. These 
parameters are loaded by a GETBPB operating system call into the BPB 
(BIOS parameter block). If these parameters are not valid, the GETBPB 
function returns a 0 instead of the address of the BPB. 


47 



Abacus 


Atari ST Disk Drives Inside and Out 


The additional information in the boot sector is the serial number of the 
diskette. This is a 24-bit number that's determined and written to the 
diskette during formatting. This number is used to verify when the diskette 
has been changed. 


Here is the complete construction of the boot sector: 


Significance 

Branch command to boot program (if present) 
Reserved fill bytes or loader 
Serial number 

Bytes per sector (512) 

Sectors per cluster (2) 

Reserved sectors (1) 

Number of FATs (File Allocation Tables) (2) 
Number of possible directory entries (112) 
Number of sectors on the diskette (720/1440) 
Medium description (unused) 

Sectors per FAT (5) 

Sectors per track (9) 

Number of sides of the diskette (1 12) 

Number of hidden sectors (0) 

Flag for COMMAND . PRG 
Flag for file or sector boot 
First sector to be loaded 
Number of sectors to be loaded 
Load address 
FAT address 

Filename (usually TOS. IMG) 

Reserved 
Boot program 

Comparison word for the checksum 

The entries marked with an asterisk (*) correspond to the BPB of the 
diskette. These entries are identical to those of MS-DOS, the operating 
system of the IBM PC. We should note that a 16-bit word is stored here, in 
the byte order low byte-high byte (for example, BPS = $00 $02 means 
$200 bytes per sector). This makes it possible for the Atari ST to read IBM 
PC diskettes. However, the ST cannot do any more than read these files, 
because the data distribution on the diskette is organized differently on the 
PC. 


Bvte# 

Marne 


$00 

BRA 


$02 

filler 


$08 

serial # 

* 

$0B 

BPS 

* 

$0D 

SPC 

* 

$0E 

RES 

* 

$10 

NFATS 

* 

$11 

NDIRS 

* 

$13 

NSECTS 

* 

$15 

MEDIA 

* 

$16 

SPF 

* 

$18 

SPT 

* 

$1A 

NSIDES 

* 

$1C 

NHID 


$1E 

EXECFLG 


$20 

LDMODE 


$22 

SSECT 


$24 

SECTCNT 


$26 

LDADDR 


$2A 

FATBUF 


$2E 

FNAME 


$39 

RES 


$3A 

BOOTIT 


$1FD 



$1FE 



48 


Abacus 


Atari ST Disk Drives Inside and Out 


A couple of comments about the entries in the boot sector: 

• The numbers in parentheses found behind some of the entries 
indicate the normal contents of these entries on a single-sided 
diskette. 

• NHID, the number of hidden sectors, is not used by the ST 
BIOS for diskettes. 

The data at $1E are of interest only if the diskette is bootable. Such a 
diskette normally contains the operating system in the form of data files 
called image files (. IMG). An executable boot sector can also be recognized 
by the text LOADER at the 3rd byte. The boot program, which is stored in 
two ROMs in older Atari STs, also recognizes such a boot sector by the 
checksum—it must be $1234 for an executable boot sector. If this is the 
case, the additional data in the boot sector has the following meaning: 

EXECFLG will be copied in the system variable cmdload. This 
flag determines whether or not the program command . PRG will 
be loaded after loading the operating system. 

LDMODE determines the loading mode. If this flag is zero, the 
file specified by FNAME will be loaded. This file is usually 
TOS . IMG. If LDMODE is not zero, sectors will be directly 
loaded, depending on SECTCNT and SSECT. 

SSECT is the logical sector at which booting starts. This variable 
is valid only if LDMODE is not zero. 

SECTCNT specifies the number of sectors to be booted. This is 
also valid only if LDMODE is not zero. 

LDADDR is the address at which the file or sectors will be 
loaded. 

FATBUF specifies the address at which the FAT and the 
directory sectors will be loaded. 

FNAME is the filename of the image file to be loaded (LDMODE 
= 0). It is constructed just like a normal filename, with eight 
characters for the name and a three-character extension. 


49 



Abacus 


Atari ST Disk Drives Inside and Out 


BOOTIT is a boot program that will be executed after the boot 
sector has been loaded. 

That is the basic construction of the boot sector. Together with what we 
have learned about the diskette format, we can start putting some of our 
knowledge into practice by writing a program for formatting diskettes. 

We can already use the Format option in the File menu to format disks. 
As we mentioned earlier, the format used by the Atari operating system TOS 
is set to 80 tracks and 9 sectors per track. However, we can physically fit 
more tracks and sectors on a diskette. 


3.2.1 Formatting program 


The program below offers some options for increasing the capacity of a 
normal diskette. It displays a menu which shows the parameters for 
formatting: 

*** Formatting program S.S. *** 


[Fl] Sides (s) : 2 

[F2 ] Tracks .: 80 

[F3] Sectors/track 9 

[F4] Drive .: A 

[F8] Format ... 

[F10] Quit ! 


Pressing a function key changes a setting or performs a function. The 

following settings are available: 

<F1>: This key toggles between one and two sides. If you are using 
a single-sided disk drive, only one side can be formatted. 

<F2>: Here you can select 80 (normal setting) or 82 tracks. It is also 
possible to use 83 tracks, but we have not included this option 
because of data loss problems. You can add this capability by 
making a minor change to the program. 

<F3>: This function key toggles between 9 and 10 sectors per track. 


50 






Abacus 


Atari ST Disk Drives Inside and Out 


<F4>: This key allows you to select either drive A or drive B. 

Always check this parameter before you start the formatting, 
to prevent accidentally erasing important data on the diskette in 
the other drive... 

<F8>: Formatting begins immediately after this key is pressed, 
indicated by the following message: 

Formatting. Please wait... 

If an error occurs, the following message appears: 

** An error occurred !! ** 

You should check the diskette to make sure that it is not write- 
protected. The error message remains onscreen until you press 
a key. 

<F10>: When are finished formatting disks, you can exit the program 
by pressing this key. 


Disks of varying storage capacities can be created by the selections possible 
with this program. Here are some values for single-sided formats: 


Tracks 

80 

82 

80 

82 


Sectors per track 
9 
9 
10 
10 


Capacity in bvtes 
357376 
366592 
398336 
408576 


As you can see from the table above, it is possible to increase the capacity of 
a single-sided diskette by up to 51200 bytes. For double-sided disks, it is 
possible to gain more than 100K. 

Here is the program. It was created with the AssemPro assembler, which 
has few differences from the DRI assembler. If you want to assemble the 
program with the DRI assembler, you must start each comment line with an 
asterisk (*), and change the ALIGN. w instruction to EVEN. 


51 




Abacus 


Atari ST Disk Drives Inside and Out 


;** Formatting-Program S.D. ** 


run: 


move .1 

#menue,dO 


bsr 

print 

;Menu output 

bsr 

getkey 


cmp.b 

#$3b,dO 


bit 

run 

/false key 

cmp.b 

#$44,dO 


bgt 

run 

/false key 

cmp.b 

#$3b,dO 

/FI ? 

bne 

notf 1 


eor 

#3,sds 

/1/2 Side 

eor 

# 1 ,sdsf 


bra 

run 



notf 1 : 


cmp.b 

#$3c,dO 

/ F2 ? 

bne 

notf 2 


eor 

# 2 ,trs 

,•80/82 Tracks 

eor 

# 2 ,trsf 


bra 

run 



notf 2 : 


cmp. b 

#$3d,dO 

/ F3 ? 


bne 

notf3 



eor 

#3,sptf 



eor 

#$1109,spt 

/9/10 Sectors 5 

>er Track 


bra run 

notf3: 

cmp.b #$3e,d0 
bne notf4 

eor #3,lw 

eor #l,lwf 

bra run 

notf4 : 

cmp.b #$42,dO 
bne notf 8 

bsr format 

bra run 

notf 8 : 

cmp.b #$44,d0 
bne run 


;F4 ? 


;Drive A/B 


;F 8 ? 

/=> Formatting 


; F10 ? 


52 


Abacus 


Atari ST Disk Drives Inside and Out 


clr -(sp) 

trap #1 

format: 

move.l #wait,dO 

bsr print 

move trsf,trsfl 

subq #l,trsfl 

floop: 

move sdsf,side 

floopl: 

bsr fmttr 

bne error 

subq #l,side 

bpl floopl 

subq #l,trsfl 

bpl floop 

setboot: 

clr ~(sp) 

moveq #2,d0 

or sdsf,dO 

move dO,-(sp) 

move.l #$1000000,-(sp) 
pea buffer 

move #$12,-(sp) 

trap #14 

add.l #14,sp 

lea buffer,aO 

clr.l dO 

cmp #9,sptf 

beq sok 

move.b #10,24(aO,dO) 

move trsf,dl 

tst sdsf 

beq sdll 

lsl #1,dl 

sdll: 

bsr addsec 

sok: 

cmp #80,trsf 

beq trok 

move #18,dl 

tst sdsf 


;Quit, return to Desktop 
;* Formatting * 

;"Formatting drive.." 


; Side 


/format one Track 

/Get other side 
/format 

/next Track 
/Boot-Sector create 
/Execute-Flag: not set 

/Disk type and number of sides 
/Serial number 
/Buffer address 

/Boot-Sector create 


/number of Boot-Sector-buffer 

/9 Sectors per Track ? 

/yes 

/set 10 SPT value 
/number of Tracks in Dl 
/I Side ? 

/yes 

/else set two sided 

/SEC + number of Tracks (Dl) 

/80 Tracks ? 

/yes 

/1 Side ? 


53 




Abacus 


Atari ST Disk Drives Inside and Out 


beq 

sdl2 

; yes 

lsl 

#1, dl 

;else double sided 

sdl2 : 

bsr 

addsec 

;SEC + 2*9 or 4*9 

trok: 

move 

#1, -(sp) 

;1 Sector 

clr. 1 

- (sp) 

;Side 0, Track 0 

move 

#1, -(sp) 

/Sector 1 

move 

lwf, -(sp) 

/Disk drive 

clr. 1 

- (sp) 


pea 

buffer 

/Buffer 

move 

#9, -(sp) 


trap 

#14 

/flopwr, Boot-Sector write 

add. 1 

#20,sp 


tst 

dO 

/Error test? 

bne 

error 

/yes: error routine 

bra 

run 

/New start 

addsec: 


/SEC = SEC + Dl 

move.b 

20 (a0,d0),d2 

;HI 

lsl 

#8,d2 


move. b 

19(aO,dO),d2 

/LO 

add 

dl, d2 


move. b 

d2, 19(aO,dO) 

/set LO 

lsr 

#8,d2 


move .b 

d2,20(aO,dO) 

/set HI 

rts 

error: 

move. 1 

#errtxt,dO 


bsr 

print 

/Error message output 

bsr 

getkey 

/wait for key press 

bra 

run 

/and new start 

fmttr: 


/one track formatting 

clr 

- (sp) 

/Virgin data 

move.1 

#$87654321,-(sp) 

/Magic-number 

move 

#1, -(sp) 

/ interleave 

move 

side, -(sp) 

/Side 

move 

trsf1,-(sp) 

/Track 

move 

spt f, — ( Sp) 

/ Sectors/Track 

move 

lwf,-(sp) 

/ drive 

clr .1 

- (sp) 


pea 

buffer 

/Track-Buffer 

move 

#10,-(sp) 


trap 

#14 

/flopfmt. Track format 


54 




Abacus 


Atari ST Disk Drives Inside and Out 


add.1 #26,sp 

tst dO 

rts 

print: 

move.l dO,-(sp) 
move #9,-(sp) 
trap #1 
addq.1 #6,sp 

rts 

getkey: 

move.w #l,-(sp) 
trap #1 
addq.l #2,sp 
swap dO 
rts 


;Test for Error 


/Text output from (DO) 


/wait for key press. 


/key code in DO.b 


/ Text and Variables: 


menue: 

dc.b 

$lb,"E***** Formatting—Program S.D 


dc. b 

10,13,10,13 


dc. b 

" [FI] Side (s) .: " 

sds : 

dc. b 

" 2",10,13 


dc. b 

" [F2] Tracks .: " 

trs: 

dc.b 

"80",10,13 


dc.b 

" [F3] Sectors/track ..: " 

spt: 

dc. b 

" 9",10,13 


dc.b 

" [ F4 ] Drive .: " 

lw: 

dc. b 

" A",10,13 


dc.b 

" [F 8 ] Format ...",10,13 


dc. b 

"[F10] Quit !", 10,13,10,13,0 

wait: 

dc. b 

"Formatting. Please wait...", 10,13,0 

errtxt 

dc.b 

"** An error occurred !! **",10,13,0 

align 

w 


sdsf: 

dc. w 

1 

trsf: 

dc .w 

80 

trsf 1 : 

dc. w 

80 

sptf: 

dc. w 

9 

lwf: 

dc. w 

0 

side: 

dc. w 

0 

BSS 



buffer 

DS.B 

8000 


END 


55 









Abacus 


Atari ST Disk Drives Inside and Out 


The program is divided into the following segments: 

1) Menu control: The screen is cleared and the menu is printed. 
After a key is pressed, the key code passed in DO is evaluated. If 
one of the CMP . B #$xx, DO comparisons match, the selected 
function will be executed. For the switch function (<F1>-<F4>), 
the switch is accomplished with the EOR command in the menu 
text and the corresponding parameter line. After the switch, the 
program branches back to start (run), except for the <F10> 
key, which ends the program via the GEMDOS TERM function. 

2) Formatting: After outputting the message Formatting . . ., the 
diskette will be formatted from the set maximum track-1 to track 
0. If double-sided formatting is enabled, the tracks on side 1 
(back) are formatted first, followed by the tracks on side 0. 

3) Creation of the boot sector: First a normal boot sector is created 
by the XBIOS PROTOBT function. Only the number of sides is 
taken into account. 

4) Correction of the boot sector: If nonstandard settings are used (10 
sectors per track, 82 tracks), the boot sector will be corrected 
accordingly. First the number of sectors per track is tested. If it is 
10, this will be placed in the SPT cell of the boot sector and then 
the number of tracks will be added to the number of sectors on 
the diskette. The selected number of tracks will then be tested and 
the sector number increased if required. 

5) Saving the boot sector: The new boot sector will be written to 
side 0, track 0, sector 1 with the help of the FLOPWR XBIOS 
function. If an error occurs, it will be displayed. 

6) Data area: This is where the strings for the menu, messages and 
variables are stored. The length of the buffer is set, but the buffer 
is not written on the diskette because it is in the . bs s area. 

Here is a BASIC program which generates the formatting program on the 
diskette, storing it under the name bigfmt. prg: 

1000 open"R",1,"a:bigfmt.prg",16 
1010 field#l,16 as bin$ 

1020 a$="":for i=l TO 16: read d$:if d$="*"then 1050 

1030 a=val("&H"+d$):s=s+a:a$=a$+chr$(a):next 


56 



Abacus 


Atari ST Disk Drives Inside and Out 


1040 

lset 

bin$=a$:rec=rec+l: 

1050 

data 

60,1A,00,00,03,00, 

1060 

data 

00 ,00,00,00,00,00, 

1070 

data 

01,FC,61,00,01,DC, 

1080 

data 

BO,3C,00,44,6E,E6, 

1090 

data 

00, 03,00, 00,02,3E, 

1100 

data 

BO,3C,00,3C,66,00, 

1110 

data 

0A,79,00,02,00,00, 

1120 

data 

00,14,OA,79,00,03, 

1130 

data 

02, 76, 60, 98,BO, 3C, 

1140 

data 

00, 00,02, 92,OA,79, 

1150 

data 

BO,3C,00, 42, 66, 00, 

1160 

data 

BO,3C,00,44,66,00, 

1170 

data 

02,B9,61,00,01,3C, 

1180 

data 

53,79,00,00,02,F8, 

1190 

data 

61, 00,00, E2, 66, 00, 

1200 

data 

53, 79,00, 00, 02,F8, 

1210 

data 

02,F4,3F,00,2F,3C, 

1220 

data 

3F, 3C, 00,12,4E, 4E, 

1230 

data 

03, 00, 42,80,OC, 79, 

1240 

data 

11,BC,00,0A,00,18, 

1250 

data 

02,F4,67,00,00,04, 

1260 

data 

00,00,02,F6,67,00, 

1270 

data 

02,F4,67,00, 00, 04, 

1280 

data 

42,A7,3F,3C,00,01, 

1290 

data 

00,00,03,00,3F,3C, 

1300 

data 

4A,40,66,00,00,IE, 

1310 

data 

14,30,00,13,D4,41, 

1320 

data 

4E,75,20,3C,00,00, 

1330 

data 

60,00,FE,5A,42,67, 

1340 

data 

3F,39,00,00,02, FE, 

1350 

data 

02,FA,3F,39, 00, 00, 

1360 

data 

3F,3C,00,OA,4E, 4E, 

1370 

data 

2F,00,3F, 3C, 00, 09, 

1380 

data 

4E,41,54,8F, 48, 40, 

1390 

data 

46,6F,72,6D,61,74, 

1400 

data 

72, 61, 6D, 20,53, 2E, 

1410 

data 

0A,0D,20,5B,46,31, 

1420 

data 

2E,2E,2E,2E,2E,2E, 

1430 

data 

46,32,5D,20,54,72, 

1440 

data 

2E,2E,2E, 2E, 3A, 20, 

1450 

data 

53, 65, 63, 74,6F, 72, 

1460 

data 

3A,20,20,39,OA, OD, 

1470 

data 

65,20,2E,2E,2E,2E, 

1480 

data 

OA,OD,20,5B, 46, 38, 

1490 

data 

2E,2E,OA,OD, 5B, 46, 

1500 

data 

OA,OD,OA, 0D,00,46, 


put l,rec:goto 1020 
00, 00, 00, 00, 00, 00, IF, 40,00, 00 
00, 00, 00, 00, 00,00,20,3C,00,00 
61,00,01,E4,B0,3C,00,3B,6D,EC 
BO, 3C, 00, 3B, 66, 00,00, 14,0A,7 9 
OA,79,00,01,00,00,02,F4,60,CC 
00,14,OA,79,00,02,00,00,02,5A 
02,F6,60,B2,B0,3C,00,3D,66,00 
00,00,02,FA,OA,79,11,09,00,00 
00,3E,66,00,00,16,OA,79,00,03 
00,01,00,00,02,FC,60,00,FF,7E 
00, OA, 61, 00,00, 12, 60, 00, FF, 6E 
FF,66,42,67,4E,41,20,3C,00,00 
33,F9,00,00,02,F6,00,00,02,F8 
33, F9, 00, 00, 02,F4,00, 00,02, FE 
00, CC, 53, 79, 00,00, 02,FE,6A,F0 
6A,DE,42,67,70,02,80,79,00,00 
01,00,00,00,48,79,00,00,03,00 
DF,FC,00,00,00,OE,41,F9,00,00 
00, 09, 00, 00, 02,FA, 67, 00, 00,IE 
32,39,00,00,02,F6,4A,79,00,00 
E3,49,61,00,00,50,OC,79,00,50 
00,16,32,3C,00,12,4A,79,00,00 
E3,49,61,00,00,30,3F,3C,00,01 
3F,39,00,00,02,FC,42,A7,48,79 
00,09,4E,4E,DF,FC,00,00,00,14 
60,00,FE,84,14,30,00,14,El,4A 
11, 82,00, 13, EO, 4A, 11, 82,00, 14 
02,D6,61,00,00,46,61,00,00,4E 
2F, 3C, 87, 65, 43, 21,3F, 3C, 00, 01 
3F,39,00,00,02,F8,3F,39,00,00 
02,FC,42,A7,48,79,00,00,03,00 
DF,FC,00,00,00,1A,4A,40,4E,75 
4E,41,5C,8F,4E,75,3F,3C,00,01 
4E,75,IB,45,2A,2A,2A,2A,2A,20 
74,69,6E,67,2D,2D,50,72,6F,67 
44,2E,20,2A,2A,2A,2A,2A,OA,OD 
5D,20,53,69,64,65,28,73,29,20 
2E,2E,3A,20,20,32,OA,OD,20,5B 
61,63,6B,73,20,2E,2E,2E,2E,2E 
38,30,OA,OD,20,5B,46,33,5D,20 
73,2F,74,72,61,63,6B,20,2E,2E 
20,5B,46,34,5D,20,44,72,69,76 
2E,2E,2E,2E,2E,2E,3A,20,20,41 
5D,20,46,6F,72,6D,61,74,20,2E 
31,30,5D,20,51,75,69,74,20,21 
6 F, 72, 6D, 61, 74,74, 69, 6E, 67,2E 


57 




Abacus 


Atari ST Disk Drives Inside and Out 


1510 data 20,50,6C,65,61,73,65,20,77,61,69,74,2E,2E,2E,0A 
1520 data 0D,00,2A,2A,20,41,6E,20,65,72,72,6F,72,20,6F,63 
1530 data 63,75,72,72,65,64,20,21,21,20,2A,2A,OA,OD,00,00 
1540 data 00,01,00,50,00,50,00,09,00,00,00,00,00,00,00,02 
1550 data 24,08,12,08,12,08,12,08,26,OA,04,06,06,04,OE,08 
1560 data OC,OE,12,OA,10,06,12,OE,1A,08,34,IE,06,06,06,08 
1570 data 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 
1580 data * 

1590 close l:if so 48541 then print"ERROR IN DATA!":end 
1610 print "Ok." 

Some comments about the program: 

• The only way to copy a normal diskette to an extended-capacity 
diskette is file by file. The operating system will not copy the 
disks directly because of the different disk formats. 

• It is not directly possible to use an extended-capacity diskette as a 
TOS system disk, because there is no loader in the boot sector. 
To make such a diskette bootable, the boot sector of another 
diskette must be copied and modified with a disk monitor to take 
into account the parameters of the extended-capacity diskette. 

• Do not use extended-capacity diskettes for storing very important 
and unique data. If the diskettes are not very high quality, one or 
more sectors can go bad in the inner tracks. 


3.2.2 The BIOS parameter block 


Back to theory. As we mentioned before, the BIOS parameter block (BPB) 
is made up of a variety of information. Let's take a closer look at this BPB. 

Some entries in this parameter block will look familiar, because they are 
also present in the boot sector. The BPB is created by calling the BIOS 
command GETBPB (number 7), provided the diskette was changed in the 
meantime. Unlike the boot sector, the data in the BPB is in the normal 
16-bit format. It is in the following order: 


recsize - Sector size in bytes (512) 

clsiz - Cluster size in sectors (2) 

clsizb - Cluster size in bytes (1024) 

rdlen - Number of directory sectors (7) 


58 




Abacus 


Atari ST Disk Drives Inside and Out 


fsiz 

- FAT size in sectors 

(5) 

fatrec 

- Start sector of the second FAT 

(6) 

datrec 

- First data sector 

(rdlen+fsiz+fatrec= 18) 

numcl 

- Number of data clusters 

(711) 

bflags 

- FAT entry size in bit 0: 

0=12 bits, 1=16 bits 

(0) 


The numbers in parentheses are the typical contents of the entries for a 
double-sided diskette. 

Now we’ll take a look at a program that reads the BIOS parameter block and 
analyzes it. The construction of the program is fairly simple. First a prompt 
that contains the title is displayed. This prompt asks you to enter a letter 
from the keyboard. This letter is either a drive specifier (a, b, c, or d) or 
the letter q. Pressing <q> ends the program and returns you to the Desktop. 

After this input, the program tests to see if a valid letter was entered. If not, 
the program is restarted. (If a <q> is entered, the program will end). 

The valid letter entered will then be converted to the value required for the 
GETBPB call (0-3) by subtracting a. The GETBPB will then be called. The 
address of the BPB will be returned in register DO. 

The entries in the BPB can now be read, printed in hexadecimal, and given 
appropriate labels. All of the information about the diskette can then be seen 
at a glance. 

Here is the program, written with the AssemPro assembler: 

;** BPB-Analyzer S.D. ** 
run: 


move.1 

#prompt,dO 


bsr 

pmsg 

/Prompt output 

bsr 

getkey 

/input the drive A-D 

cmp 

=#= 

a 

o 

/Quit ? 

beq 

quit 

/yes => Desktop 

move 

dO, d6 

/save charavter 

bsr 

pcrlf 

/CR output 

sub 

#'a',d6 

/value to small 

bmi 

run 

/false input 

cmp 

#3,d6 


bgt 

run 

/false input 


59 


Abacus 


Atari ST Disk Drives Inside and Out 


move 

d6,-(sp) 

;Device-Nr. 

move 

#7, -(sp) 


trap 

#13 

;GETBPB-Function 

addq.1 

#4, sp 


tst. 1 

dO 


beq 

run 

/Error ! 

move.1 

dO, a5 

/store BPB-Address 

bsr 

pnext 


move.1 

#bps,dO 


bsr 

pline 

/"Bytes per Sector" 

bsr 

pnext 


move.1 

#spc,dO 


bsr 

pline 

/"Sectors per Cluster" 

bsr 

pnext 


move.1 

#bpc,dO 


bsr 

pline 

/"Bytes per Cluster" 

bsr 

pnext 


move.1 

#dirsec,dO 


bsr 

pline 

/"Directory-Sectors" 

bsr 

pnext 


move.1 

#fatsec,dO 


bsr 

pline 

/"FAT-Sectors" 

bsr 

pnext 


move.1 

#fat2s,dO 


bsr 

pline 

/"Start-Sector of 2. FAT 

bsr 

pnext 


move. 1 

#datsec,dO 


bsr 

pline 

/"Start-Sector of Data" 

bsr 

pnext 


move. 1 

#datc,dO 


bsr 

pline 

/"Data cluster" 

move 

#'$',d0 


bsr 

pchar 

/"$" output 

move 

#12,dO 

/12 Bit 

btst 

#0,(a5) 

/correct ? 

beq 

bitsl2 

/yes 

move 

#16,dO 

/else 16 Bit 


60 




Abacus 


Atari ST Disk Drives Inside and Out 


bitsl2: 


bsr 

phexbyt 


move .1 

#fatbit,dO 


bsr 

pline 

/"Bits per FAT-entry" 

bra 

run 

/ready => New start 

quit: 


/ Exit to Desktop 

clr 

- (sp) 


trap 

#1 


getkey: 


/Get Key -> DO 

move 

# 1 , -(sp) 


trap 

#1 


and. 1 

#$ff,dO 


addq .1 

rts 

# 2 , sp 


pline: 


/Print Line/CR 

bsr 

pmsg 


pcrlf: 


/Print CR, LF 

move 

#10,dO 


bsr 

pchar 


move 

#13,dO 


pchar: 


/Print Character DO 

move 

dO,-(sp) 


move 

# 2 , -(sp) 


trap 

#1 


addq .1 

rts 

#4, sp 


pmsg: 


/Print Line (DO) 

move .1 

dO, -(sp) 


move 

#9, -(sp) 


trap 

#1 


addq 

rts 

# 6 , sp 


pnext: 


/get next word and output 

move 

#'$',d 0 


bsr 

pchar 

/"$" output 

move 

(a5) +, dO 


phexword: 


/Print Hex-Word DO 

moveq 

#3, dl 


bra 

phexl 



61 


Abacus 


Atari ST Disk Drives Inside and Out 


phexbyt: ;Print Hex-Byte 

moveq #l,dl 
rol.l #8,d0 

phexl: 

rol.l 
move.1 
move.1 
bsr 

move.1 
move.1 
dbra 
rts 

phexnib: 

and.1 #$7f,d6 

swap dO 

and.l #$0f,d0 
add.b #$30,dO 
cmp.b #$3a,d0 
bcs phexn 

add.b #7,d0 


phexn: 

bra pchar /Nibble output 


prompt: 

dc .b 

■■*** BPB-Analyzer S.D. ***",10,13 


dc.b 

"Input disk drive (a-d) or",10,13 


dc .b 

"'q' for Quit : ",0 

bps: 

dc.b 

" Bytes per Sector",0 

spc: 

dc. b 

" Sectors per Cluster",0 

bpc: 

dc. b 

" Bytes per Cluster",0 

dirsec: 

dc.b 

" Directory-Sectors",0 

fatsec: 

dc. b 

" FAT-Sector",0 

fat2s: 

dc.b 

": Start-Sector 2.FAT",0 

datsec: 

dc.b 

Start-Sector of data",0 

date: 

dc.b 

" Data-Cluster",0 

fatbit: 

dc.b 

" Bits per FAT-entry",10,13, 0 


end 

Here is the BASIC loader. It creates the BPB analysis program as 
bpbana . TOS on the diskette: 

1000 open"R",1,"a:bpbana.tos",16 
1010 field#l,16 as bin$ 

1020 a$="":for i=l TO 16:read d$:if d$="*"then 1050 


#4, dO 
dO,-(sp) 
dl,-(sp) 

phexnib ;one Nibble (0-F) output 

(sp)+,dl 
(sp)+,dO 
dl,phexl 


62 




Abacus 


Atari ST Disk Drives Inside and Out 


1030 

1040 

1050 

1060 

1070 

1080 

1090 

1100 

1110 

1120 

1130 

1140 

1150 

1160 

1170 

1180 

1190 

1200 

1210 

1220 

1230 

1240 

1250 

1260 

1270 

1280 

1290 

1300 

1310 

1320 

1330 

1340 

1350 

1360 

1370 

1380 

1390 

1400 

1410 

1420 

1430 

1440 

1450 

1470 


a-val("&H"+d$):s=s+a:a$=a$+chr$(a):next 


lset 

bin$=a$:rec= 

II 

a> 

0 

+ 

put 

• 1 , 

, rec:goto 

1020 




data 

60, 

1A, 

00 , 

00 , 

, 02 , 

,44, 

00 , 

00 , 

, 00 , 

00 , 

00 , 

00 , 

00 , 

00 , 

, 00 , 

, 00 

data 

00 , 

00 , 

00 , 

00 , 

, 00 , 

, 00 , 

O 

o 

00 , 

o 

o 

00 , 

o 

o 

00 , 

20 , 

3C, 

, 00 , 

, 00 

data 

01 , 

54, 

61, 

00 , 

. 00 , 

, FA, 

61, 

00 , 

, 00 , 

CA, 

B0, 

7C, 

00 , 

71, 

, 67, 

, 00 

data 

00 , 

BE, 

3C, 

00 , 

,61, 

. 00 , 

00 , 

DO, 

, 9C, 

7C, 

00 , 

61, 

6 B, 

DE, 

, BC, 

. 7C 

data 

00 , 

03, 

6 E, 

D 8 , 

, 3F, 

, 06, 

3F, 

3C, 

, 00 , 

07, 

4E, 

4D, 

58, 

8 F, 

, 4A, 

, 80 

data 

67, 

CA, 

2 A, 

40, 

, 61, 

, 00 , 

00 , 

D4, 

, 20 , 

3C, 

00 , 

00 , 

01 , 

9A, 

, 61, 

,00 

data 

00 , 

A2, 

61, 

00 , 

. 00 , 

,C 6 , 

20 , 

3C, 

, 00 , 

00 , 

01 , 

AC, 

61, 

00 , 

, 00 , 

, 94 

data 

61, 

00 , 

00 , 

B 8 , 

. 20 , 

. 3C, 

00 , 

00 , 

, 01 , 

Cl, 

61, 

00 , 

00 , 

86 , 

. 61, 

, 00 

data 

00 , 

AA, 

20 , 

3C, 

. 00 , 

. 00 , 

01 , 

D4, 

, 61, 

00 , 

00 , 

78, 

61, 

00 , 

, 00 , 

, 9C 

data 

20 , 

3C, 

00 , 

00 , 

, 01 , 

,E7, 

61, 

00 , 

, 00 , 

6 A, 

61, 

00 , 

00 , 

8 E, 

, 20 , 

, 3C 

data 

00 , 

00 , 

01 , 

F4, 

. 61, 

. 00 , 

00 , 

5C, 

, 61, 

00 , 

00 , 

80, 

20 , 

3C, 

. 00 , 

, 00 

data 

02 , 

09, 

61, 

00 , 

. 00, 

■4E, 

61, 

00 , 

. 00, 

72, 

20 , 

3C, 

00 , 

00 , 

. 02 , 

,20 

data 

61, 

00 , 

00 , 

40, 

. 30, 

, 3C, 

00 , 

24, 

. 61, 

00 , 

00 , 

48, 

30, 

3C, 

. 00, 

, OC 

data 

08, 

15, 

00 , 

00 , 

, 67, 

, 00, 

00 , 

06, 

, 30, 

3C, 

00 , 

10 , 

61, 

00 , 

, 00, 

, 5A 

data 

20 , 

3C, 

00 , 

00 , 

02 , 

. 2E, 

61, 

00 , 

, 00, 

1A, 

60, 

00 , 

FF, 

30, 

42, 

, 67 

data 

4E, 

41, 

3F, 

3C, 

. 00, 

.01, 

4E, 

41, 

,C0, 

BC, 

00 , 

00 , 

00 , 

FF, 

,54, 

. 8 F 

data 

4E, 

75, 

61, 

00 , 

, 00, 

. 1A, 

30, 

3C, 

. 00, 

0A, 

61, 

00 , 

00 , 

06, 

, 30, 

, 3C 

data 

00 , 

0D, 

3F, 

00 , 

. 3F, 

, 3C, 

00 , 

02 , 

, 4E, 

41, 

58, 

8 F, 

4E, 

75, 

, 2F, 

, 00 

data 

3F, 

3C, 

00 , 

09, 

. 4E, 

■41, 

5C, 

4F, 

■4E, 

75, 

30, 

3C, 

00 , 

24, 

, 61, 

,E2 

data 

30, 

ID, 

72, 

03, 

. 60, 

. 00, 

00 , 

06, 

72, 

01 , 

El, 

98, 

E9, 

98, 

■ 2F, 

00 

data 

2 F, 

01 , 

61, 

00 , 

00 , 

. OC, 

22 , 

IF, 

20 , 

IF, 

51, 

C9, 

FF, 

F0, 

4E, 

. 75 

data 

CC, 

BC, 

00 , 

00 , 

00 , 

7F, 

48, 

40, 

CO, 

BC, 

00 , 

00 , 

00 , 

OF, 

DO, 

3C 

data 

00 , 

30, 

B0, 

3C, 

00 , 

3A, 

65, 

00 , 

00 , 

06, 

DO, 

3C, 

00 , 

07, 

60, 

A2 

data 

2 A, 

2A, 

2 A, 

20 , 

42, 

50, 

42, 

2D, 

41, 

6 E, 

61, 

6 C, 

79, 

7A, 

65, 

72 

data 

20 , 

53, 

2E, 

44, 

2E, 

20 , 

2 A, 

2 A, 

2A, 

0A, 

0D, 

49, 

6 E, 

70, 

75, 

74 

data 

20 , 

64, 

69, 

73, 

6 B, 

20 , 

64, 

72, 

69, 

76, 

65, 

20 , 

28, 

61, 

2D, 

64 

data 

29, 

20 , 

6 F, 

72, 

0A, 

0D, 

27, 

71, 

27, 

20 , 

66 , 

6 F, 

72, 

20 , 

51, 

75 

data 

69, 

74, 

20 , 

3A, 

20 , 

00 , 

20 , 

42, 

79, 

74, 

65, 

73, 

20 , 

70, 

65, 

72 

data 

20 , 

53, 

65, 

63, 

74, 

6 F, 

72, 

00 , 

20 , 

53, 

65, 

63, 

74, 

6 F, 

72, 

73 

data 

20 , 

70, 

65, 

72, 

20 , 

43, 

6 C, 

75, 

73, 

74, 

65, 

72, 

00 , 

20 , 

42, 

79 

data 

74, 

65, 

73, 

20 , 

70, 

65, 

72, 

20 , 

43, 

6 C, 

75, 

73, 

74, 

65, 

72, 

00 

data 

20 , 

44, 

69, 

72, 

65, 

63, 

74, 

6 F, 

72, 

79, 

2D, 

53, 

65, 

63, 

74, 

6 F 

data 

72, 

73, 

00 , 

20 , 

46, 

41, 

54, 

2D, 

53, 

65, 

63, 

63, 

74, 

6 F, 

72, 

00 

data 

3A, 

20 , 

53, 

74, 

61, 

72, 

74, 

2D, 

53, 

65, 

63, 

74, 

6 F, 

72, 

20 , 

32 

data 

2E, 

46, 

41, 

54, 

00 , 

3A, 

20 , 

53, 

74, 

61, 

72, 

74, 

2D, 

53, 

65, 

63 

data 

74, 

6 F, 

72, 

20 , 

6 F, 

66 , 

20 , 

64, 

61, 

74, 

61, 

00 , 

20 , 

44 , 

61, 

74 

data 

61, 

2D, 

43, 

6 C, 

75, 

73, 

74, 

65, 

72, 

00 , 

20 , 

42, 

69, 

74, 

73, 

20 

data 

70, 

65, 

72, 

20 , 

46, 

41, 

54, 

2D, 

65, 

6 E, 

74, 

72, 

79, 

0A, 

0D, 

00 

data 

00 , 

00 , 

00 , 

02 , 

3C, 

0E, 

0E, 

0E, 

0E, 

0E, 

0E, 

0E, 

26, 

00 , 

00 , 

00 

data 

★ 

















close 1:if s<> 40341 then print"ERROR IN DATA!":end 
print "Ok." 


63 


Abacus 


Atari ST Disk Drives Inside and Out 


When the computer is turned on, the BPB data are not available. The 
operating system doesn't create the BPB until after booting, when the 
number of connected drives and their designations are known. 

If you have an early model of the ST (without TOS in ROM), the System 
Disk must first be booted. Booting also occurs if the computer contains an 
operating system but the disk contains a bootable operating system 
(TOS. IMG) and the boot sector is executable. 

Booting takes place in four steps: 

1) The boot sector is loaded and the boot program contained in it is 
executed. 

2) The FAT and the directory are loaded from the current diskette. 

The loader searches for the given filename (usually TOS . IMG). 

If it is not found, it will return an error message. 

3) TOS . IMG is loaded at memory address $40000. 

4) The loaded program is started. 

The file TOS . IMG, for its part, consists of three parts: 

• A relocator, which is a program that moves the operating system 
to the address at which it was intended to run ($6100). This 
program clears the screen, moves the TOS image block to its 
original address and then starts it there. 

• The operating system data (BIOS, XBIOS). 

• The GEM data and the Desktop program. 

As you can see, the construction of the operating system in the file 
TOS . IMG is pretty complicated. The built-in TOS, which is contained in 6 
PROM chips (Programmable Read Only Memory), is naturally somewhat 
shorter because it contains only the operating system with GEM and no 
relocator. 

Let's continue looking at data structures on the disk with a discussion of the 
construction and management of the directory. 


64 



Abacus 


Atari ST Disk Drives Inside and Out 


3.3 The directory 


On single-sided disks the directory starts at track 1, sector 3 and occupies 7 
sectors. In each entry it stores a whole set of data in addition to the filename 
and extension, data which is more or less important for the management of 
the diskette. 

Each entry in the directory consists of 32 bytes, which contain all of the 
information about the file. These 32 bytes are divided into eight data fields, 
which are constructed as follows: 


1) Filename 8 bytes 

2) File type (extension) 3 bytes 

3) Attribute 1 byte 

4) Reserved 10 bytes 

5) Time 2 bytes 

6) Date 2 bytes 

7) First cluster 2 bytes 

8) File size 4 bytes 


The first field contains the filename. This name consists of ASCII 
characters, letters and numbers only. Furthermore, only uppercase letters 
are used. The name is limited to eight characters. If the name has fewer than 
eight characters, the remaining characters will be blank spaces. 

If the first byte of a name is zero, it means that the entry has never been 
used. If the file was already used and then erased, this byte will contain a 
229 ($E5). If the first character of the name is a period (.), the entry is for a 
special subdirectory: a folder. 

The following field contains the file type, also called the extension. This 
extension is limited to three characters (such as prg, TOS, bas, etc.) and is 
also padded with spaces. Again, only uppercase letters are used. 

After this comes the file attribute byte. It contains a bit code for the status of 
this entry or file. The meanings of these bits are as follows: 

Bit Meanin2 when set Ill Bit Meaning when set (1) 

0 read only 1 hidden file 

2 system file 3 entry is the disk name 

4 entiy is a file 5 file was changed 


65 


Abacus 


Atari ST Disk Drives Inside and Out 


After this byte are 10 bytes which are not used. They are reserved and may 
be used by later versions of TOS. 

Following these are two bytes which contain the time of the last 
modification of the file. The time is specially coded to save space. The 16 
bits of the time entry are divided into three sections: hours, minutes, and 
seconds. This division looks like this: 

Example: 19:21:34 

Hour Minute Second/2 
10011 010101 10001 

The clock in the ST reports the time only in two-second increments, which 
is why the lowest five bits of the time contain a 17. 

The next field in the directory contains the date of the last modification of 
the file. The division into year, month, and day is done like the time. Only 
seven bits are reserved for the year, which is why the number 1980 must be 
added to the value returned. 

Example: 5/12/1986 

Year Month Day 
0000110 0101 01100 

The seventh field of the directory contains the number of the first cluster on 
the disk which can be used by a file. Files are stored on the disk starting 
with this cluster, which usually consists of two sectors. More information 
about what happens after this can be found in the next section. 

The last field contains the length of the file in bytes. It should be noted that 
fewer bytes may be read than are indicated here, which also depends on the 
FAT. The file length should only be seen as the maximum file length. 

With this information about the construction of the directory on the diskette, 
you can now analyze the division of the diskette using a disk monitor. Many 
results can be obtained by changing the values, but most of these 
manipulations lead to unpleasant results. For this reason, it is a good idea to 
work with a copy of the diskette rather than risk destroying the original. 

If we wanted to write a program which read the directory of a disk, we 
would have to prepare a buffer for the expected data before the 


66 




Abacus 


Atari ST Disk Drives Inside and Out 


corresponding operating system function was called. The address of this 
buffer is designated the Disk Transfer Address (DTA). 

This buffer is 44 bytes long and must be specified to the operating system 
by calling a special function. Once this is done, the search for directory 
entries can begin. The function SFIRST (Search FIRST) looks for the first 
matching entry in the directory, and SNEXT (Search NEXT) looks for 
additional entries. Entries which are found by either function are loaded into 
the buffer at the DTA. 

After calling one of these functions, the buffer contains all of the 
information that also appears in the directory window on the Desktop. The 
division of the data is as follows: 


Bvte(s) 

.Contents 

0...20 

Reserved 

21 

File attribute 

22,23 

Time of modification 

24,25 

Date of modification 

26...29 

File size in bytes (LO, HI) 

30...43 

Filename and extension 


The machine language routine below sets the DTA and then searches the 
directory for the specified filename. If the name given is simply * . *, the 
first entry that corresponds to the given attribute will be returned. If no 
matching entry is present, the function will return error number - 33 (File 
not found) in register DO. Otherwise this register will contain zero. 


MOVE.L 

#BUFFER,-(SP) 

★ 

Pass DTA 

MOVE 

#$1A,—(SP) 

★ 

SETDTA function number 

TRAP 

#1 

★ 

Call operating system 

ADDQ.L 

#6, SP 

★ 

Repair stack 

MOVE 

#%11001,-(SP) 

★ 

File type: all files 

MOVE.L 

#NAME,-(SP) 

★ 

Address of the filename 

MOVE 

#$4E,-(SP) 

★ 

SFIRST function number 

TRAP 

#1 

★ 

Call operating system 

ADDQ.L 

#8, SP 

★ 

Repair stack 

TST 

DO 

★ 

Found 

BNE 

NOTHING 

★ 

no 

etc. 





BUFFER: .ds.b 44 * Space for the data 

NAME: .ds.b "*.*",0 * All names allowed 


67 



Abacus 


Atari ST Disk Drives Inside and Out 


To search for the next entry, all we need is: 


MOVE #$4F,-(SP) 
TRAP #1 
ADDQ.L #2,SP 
TST DO 

BNE NOTHING 


* SNEXT function number 

* Call operating system 

* Repair stack 

* Found 

* no 


We can easily write a program to output the directory of a diskette to the 
printer, for example. Such a program, which prints the entire directory 
including the contents of all folders, is found in section 5.3. 


If you look at the directory in the Desktop, you will see the name, 
extension, date, time, and length of the file. When you then click a 
program, the operating system needs to know not only where the file begins 
on die disk, but also where the rest of the file is located. This information is 
contained in the FAT, which we'll look at next. 


3.4 The FAT 


The FAT (File Allocation Table) normally occupies five sectors on a 
single-sided diskette. It usually starts at track 0, sector 2 of side 0. The size 
of this table varies depending on the format used. The table is used to store 
the distribution of each file on the disk. 

The reason for this lies in the fact that a file does not necessarily consist of 
consecutive sectors. Sectors which used to belong to a deleted file are 
released for storing new data. A new file being written to the disk would be 
assigned to such free sectors. Occupied sectors are simply skipped. 

Each sector must therefore have an entry in the FAT to be recognized as 
either free or allocated. In order to keep the size of the FAT down, every 
two sectors are grouped together and designated as a cluster. Clusters are 
numbered from 2 to the end of the disk, and the FAT then contains only one 
entry for every two sectors. 

Each entry in the FAT is normally 12 bits long. Some formats use 16-bit 
entries, but we will not go into that here. Twelve-bit FAT entries mean that 
two entries occupy three bytes. 


68 




Abacus 


Atari ST Disk Drives Inside and Out 


The first two entries of the FAT contain format information, which is why 
the numbering starts at 2. Every other entry represents a cluster. A zero in 
an entry means that the corresponding cluster is free. 

Naturally, this does not mean that the sectors don't contain any data, since a 
deleted file isn't actually removed from the disk. When a file is deleted, all 
that happens is that the first letter of the name in the directory is changed to 
$E5 and the cluster belonging to the file are released with zeroes in the FAT. 
The data itself is still present, but hard to find. 

If a FAT entry contains $FF7, the cluster is unusable. Such clusters are 
recognized and marked during formatting. If a disk is physically damaged in 
some way (e.g., scratched), you will notice that the capacity announced 
after formatting is less usual. However, if such an error occurs in track 0 or 
1, the entire diskette is unusable, because these tracks are supposed to 
contain the boot sector, the FAT, and the directory. 

When a file is to be loaded, the operating system takes the number of the 
first cluster of the file from the directory entry. The FAT entry of this cluster 
then contains the number of the next cluster in the file. The FAT entry of 
this cluster in turn contains the next number, and so on, until an entry 
contains $FF. This means that this cluster is the last in the file. 

A disk monitor can also be used to make changes to the FAT. However, the 
probability of data loss from doing this is extremely high—be sure to make 
a copy of the disk before you change anything in the FAT. 


3.5 Program construction 


The Atari ST has a large amount of memory which can hold more than one 
program at a time. In fact, it is possible to place several programs in 
memory at the same time and execute them. Simple examples are the desk 
accessories, which run in the "background" while an application is running. 

This open memory division causes a problem. When we used to program 
8-bit computers, we were used to writing machine language programs that 
would be stored at a specific location in memory and would run there. This 
is because the machine language program would address the memory 
directly or branch via a specific address. 


69 




Abacus 


Atari ST Disk Drives Inside and Out 


But this is impossible on the Atari ST. How can a programmer know in 
advance where his program will be loaded, and whether or not another 
program is already resident? 

Another problem is that the operating system must know the size of the 
program and how much memory it needs to run. If the program needs 
additional memory for storing information, this memory may not be 
overwritten by other programs. 

As you can see, it won't work if a program file on the disk contains nothing 
more than the program data themselves. The construction of such a file is 
the subject of this section. 

An executable program on the disk (. PRG, . TOS, and . TTP files) is 
divided into four segments. These segments are the file header, the program 
with data field, the symbol table (if one exists) and relocation data (if 
present). 

Let's look at the first part: the header. 


3.5.1 The program header 


The header is 14 bytes long and contains the lengths of the individual 
segments. The construction of the header is as follows: 


$ 00,$01 

$02-$05 

$06409 

$0A-$0D 

$0E-$11 

$1241B 


Contents 

$601 A, the machine language command BRA *+$ 1 A 
Length of the program segment (text) 

Length of the data segment (data) 

Length of the additional storage segment (bss) 

Length of the symbol table 
00, reserved 


The first entry is a machine language command which branches the program 
execution to the start of the program segment. Following this is the length 
of the program segment. This segment, generally called the "text" segment, 
contains the program itself. All addresses which the program uses are set up 
so that the start of the program is taken as address 0. Data contained in this 
segment are not changed. 


70 



Abacus 


Atari ST Disk Drives Inside and Out 


The next entry contains the length of the data segment. This segment must 
follow the program immediately. In a machine language program, the 
separation between the text and data segments is made with a data 
instruction. The initialized data, such as strings or tables, are stored here. 
Uninitialized data, like buffers for disk operations or temporary storage, are 
contained in the next segment. 

The fourth entry of the header contains the length of this additional storage. 
This memory area is called bss. After the program is loaded this memory 
area will be made available to the program. At the same time, other 
applications will be prevented from using it. Its contents are not defined—it 
must be filled by the program. The advantage of the bss segment over the 
data segment is that this area does not have to be stored in the disk file. 

Entry number five contains the length of the symbol table. Such a table is 
seldom present, because it plays no role in the function of the program. A 
symbol table is appended to the program by a compiler or assembler if the 
you desire. The symbols correspond to the labels used in the source 
program for routines or variables. The advantage of such a table is that a 
symbolic debugger like SID can include labels in a disassembly of the 
program. Once the test and development phase of a program is completed, 
the symbol table should be left off to save space. 

Each entry in the symbol table is seven words long, and contains the name, 
type, and value of the symbol: 

lixik Contents 

$0-$7 Symbol name, ends with zero 

$8-$9 Symbol type: relocatable, global, or external 

$A-$C Value, such as address, register number, direct value, etc. 

The entire symbol table of a program can be read and printed with the 
program NM68. To do this, enter the foil wing line from the command 
prompt: 

NM68 filename 

By adding >prn : to the command line, the output of NM68 can be directed 
to the printer. Otherwise the output is displayed on the screen. 

Back to the construction of the program header: The remaining bytes from 
$12 to $ IB are reserved for later use, and must be zero. 


71 



Abacus 


Atari ST Disk Drives Inside and Out 


Immediately following the header is the program. As we said, the program 
can really only work at address $0000. In order to make it run at the address 
at which it was loaded, all absolute addresses which occur in the program 
must be changed by adding the actual starting address of the program to the 
addresses contained in the program. But how does the operating system 
know that it has to make these changes, or where the absolute address are 
located in the program? The answer is called a relocation table. 


3.5.2 The relocation table 


Following the symbol table in the program file is the relocation table. This 
table contains the distances between the longwords which must be 
relocated. The first longword in this table specifies the offset of the first 
long word to be changed from the start of the program. After this, bytes are 
used whose values give the distances between the current longword and the 
next longword to be changed. If the distance between two such longwords 
is greater than 254, bytes of value 1 will be inserted until the distance to the 
next longword is less than 255. 

The first byte which contains a zero indicates the end of the relocation table. 
This is also the end of the entire program file on the disk. 

When a program is loaded, the operating system places the program at a free 
location in memory and then relocates it. The distribution of the program in 
memory is somewhat different than it was on the disk. Before the actual 
program (which the data and bss segments follow) lies what is called the 
base page. This 256-byte-long base page is another header, which contains 
information about the actual distribution of the program in memory. The 
base page is laid out as follows: 


Bvte 

Length 

Lfinlents 

00 

4 

Start address of the working memory 

04 

4 

HI address of the working memory + 1 

08 

4 

Start address of the program 

OC 

4 

Length of the program segment in bytes 

10 

4 

Start address of the data segment 

14 

4 

Length of the data segment in bytes 

18 

4 

Start address of the bss segment 

1C 

4 

Length of the bss segment in bytes 

2C 

4 

Pointer to the "environment string" 

80 

80 

Command line text (for . TTP programs) 


72 



Abacus 


Atari ST Disk Drives Inside and Out 


All other entries in the base page are reserved. 

The computer isn't the only one that needs the information in the base page. 
A program can also make good use of it. The best example of this is the 
command line. If the program is of type . TTP, the operating system 
displays a dialog box when the program is called in which die user can enter 
the command line. This line can then be evaluated by the program. 

To get the address of the command line, a command sequence like the 
following must be at the start of the program: 

run: MOVE.L 4(SP),A0 ;Address of the base page 

LEA $80(AO),AO 

AO now contains the address of the command line, and the line can be 
processed. 


3.6 Hard disk format 


Now let's turn to the hard disk. Because of its enormous storage capacity, 
the hard disk's organization is not quite so simple as that of the diskette. A 
hard disk is divided into four individual sections, each of which contains a 
boot sector. These individual sections are called partitions. 

The first sector on the hard disk (logical sector 0) contains the information 
about the partitioning of the hard disk. This information is stored as 
follows: 


Bvte 

Name 

Meaning 

$1C2 

hd 

siz 

Total size of the hard disk in logical sectors 

$1C6 

P0 

fig 

Partition 0 exists if pO f lg>0 




If bit 7, booting starts here 

$1C7 

pO 

id 

Partition ID (GEM) 

$1CA 

pO 

St 

Logical sector # of the first sector in the partition 

$1CE 

p°_ 

siz 

Size of the partition in sectors 

$1D2 

Pi 

fig 


$1D3 

Pi 

id 

see above, partition 1 

$1D6 

Pi 

St 



73 





Abacus 


Atari ST Disk Drives Inside and Out 


Bxt.e. 

Name 

Meaning 

$1DA 

pl_siz 


$1DE 

p2 fig 


$1DF 

p2 id 

see above, partition 2 

$1E2 

p2 st 


$1E6 

p2 siz 


$1EA 

p3 fig 


$1EB 

p3 id 

see above, partition 3 

$1EE 

p3 st 


$1F2 

p3 siz 


$1F6 

bsl st 

Starting sector of the bad sector list 

$1FA 

bsl cnt 

Number of defective sectors 


The bad sector list is created when the diskette is formatted. It contains a list 
of the defective sectors which could not be formatted. The table is usually 
stored at the end of the hard disk. 

The operating system uses the variable p*_f lg to determine whether the 
given partition exists or not ( p*_f lg not equal to zero). The first sector of 
each partition contains a boot sector which contains the BPB. The operating 
system boots from the first boot sector whose p*_flg has bit 7 set. 

Note: A program for analyzing and displaying the partition parameters is 
found in Section 5.1.1.4. 


74 





Chapter Four 






Abacus 


Atari ST Disk Drives Inside and Out 


The disk drives 


Probably the most common media for data storage are floppy diskettes. 
These disks, measuring 3 1/2 and 5 1/4 inches in diameter have certain 
advantages. The first is the price. If a 3 1/2" diskette costs about two dollars 
and stores 360K of data, this comes out to a little over a half a cent per 
kilobyte. The price per kilobyte is even less with 5 1/4" diskettes. Since no 
technical problems prevent the use of 5 1/4" diskettes on the Atari, this cost 
advantage might play a role in which diskette format you'll select. Some ST 
owners have connected both 3 1/2" and 5 1/4" drives to their computers. 

Another advantage that diskettes have over hard disks is that you can easily 
switch between different diskettes. This means that, at least in theory, a disk 
drive can manage an unlimited amount of data. Also, diskettes are well- 
suited for copying, exchanging and backing up programs and data. 

But we should also mention the disadvantages. Except for storage on audio 
cassette tapes, diskettes are the slowest form of data storage. The Atari ST 
drives compare favorably with the competition because they allow relatively 
fast data transfer, using various technical tricks in the ST. 

Let's look at floppy diskettes in detail. 


4.1 Floppy diskette functions 


When the ST computer needs data from a floppy diskette in one of its 
drives, various functions are initiated within the disk drive itself. First of all 
the drive motor is switched on. If two drives are connected, both of them 
will run, because the signal line responsible for the motor control from the 
ST is connected to both drives. The advantage of this is that copying from 
drive to drive is faster—time isn't wasted waiting for the motors to reach the 
correct speed. 

The next step is to select a single drive's address. This is done via the drive 
select line. If a disk drive detects that it is being accessed, the BUSY light 
goes on and shows that the device is operating. 

Now comes the decision whether data should be read from or written to the 
diskette. First the ST must specify the exact track on which the data lies. 


77 


Abacus 


Atari ST Disk Drives Inside and Out 


These tracks are rings that are organized concentrically on the diskette. The 
read/write head is then moved to a location on the diskette by a small arm, 
gliding above the rotating diskette to this track's location. 

The stored data is distributed on these tracks with a system that records and 
reads the data items as tiny magnetic pulses on the surface of the diskette. 
To make the distribution of data on a track a little easier to manage, the 
tracks are divided into sectors. Each track has nine such sectors. In turn, 
each sector contains 512 bytes of actual data. A sector really contains more 
data than stated, but this additional data is not immediately accessible. 
(We'll discuss these special bytes in a later section). 

The read/write head moving over the rotating magnetic diskette contains a 
small coil. This coil serves as a magnetic receiver, and recognizes the 
magnetic pulses that represent the data bits. This method is similar to that 
used by an audio tape recorder—but much greater precision is required for a 
diskette. The read/write head can exactly locate every one of almost three 
million bits on a disk of about 30 square centimeters—the surface area of a 
3 1/2" diskette. A single byte, which consists of 8 bits, is stored in a surface 
of only 0.008 square millimeters! 

If the computer needs data from the diskette, it requests an individual sector 
from the disk. Through a complicated process, the disk controller built into 
the computer decides which of the stream of bits arriving at the read/write 
head belong to the sector. These data bits are then selected, and its resulting 
512 bytes are sent to the computer. 

All of these procedures present many technical problems for the disk drive 
manufacturers. The mechanism that positions the head must place it exactly 
on the desired track (approximately 0.2 mm wide). Then the magnetic 
pulses which come from the rotating disk must be recognized as zeros or 
ones. At 300 rotations per minute, there are only about 0.5 microseconds 
available to read each bit. It's the job of the drive's electronics to sort 
through the desired information from a huge pool of bits. This is achieved 
through what are called synchronization bytes. The synchronization bytes 
are stored at the start of each sector on the disk. 

As we have seen, a disk drive is an extremely complicated device. We'll 
only look at the rudimentary construction of the system that processes the 
information on the diskettes. 


78 



Abacus 


Atari ST Disk Drives Inside and Out 


4.2.1 The DMA chip 


Let's start with the ST computer itself. The disk drive sends the requested 
data through the cable, which arrive at the computer as a flood of bytes. 
This data must be placed somewhere in memory to be able to use it again. 
Most computers use their Central Processing Unit (CPU) to receive the data 
and place it in memory. This means that the speed at which data can be 
received is limited by the speed of the microprocessor. 

The Atari ST does things differently, however. Data is received and 
distributed in memory by a special component which has direct access to the 
memory just like the CPU. This component is the DMA (Direct Memory 
Access) chip. The DMA chip is under the control of the CPU, but it 
performs its task completely independent of the processor. As a result, the 
CPU can perform other tasks while data is being transferred. Moreover, the 
DMA chip can move data much faster than the CPU could. 

The result of this advanced feature is that a very high data transfer rate for 
diskette operations can be achieved—especially for hard disk operations. 

The DMA chip occupies the following memory locations in the Atari ST: 

$FF8604 FDC access/sector count. This is where the registers of the 
DMA chip or the FDC chip are accessed, the selection of 
which is determined by $FF8606 

$FF8606 DMA mode/status. Bits 0-2 reflect the status of the DMA 
and FDC chips when reading. Writing to this 16-bit 
register sets the mode of the DMA chip. 

$FF8609 DMA memory vector HI byte 

$FF860B DMA memory vector MID byte 

$FF860D DMA memory vector LO byte 

These three bytes make up the 24-bit address at which or from which 
data is to be transferred by the DMA chip. These bytes must be stored 
in the order LO, MID, HI. 


79 



Abacus 


Atari ST Disk Drives Inside and Out 


The DMA chip used in the ST is connected directly to the hard disk 
interface. The connection to the floppy disk drives is not tied directly to the 
DMA chip. Between this connection and the DMA chip is a component that 
prepares die serial data arriving from the disk drive or sends the data to the 
drive serially. This component is the floppy diskette controller, which also 
controls the functions of the drive. The next section explains the 
programming of these two devices. 


4.2.2 The disk controller 


This lengthy section deals with the WD1772 floppy diskette controller 
(hereafter referred to as the FDC, or simply the controller) used in the Atari 
ST. For the description of this component, we gathered all of the available 
information and data sheets on the chip that we could find. Naturally, this 
alone wasn't good enough for a comprehensive treatment, because theory 
and practice often differ from each other. It was necessary to experiment 
with the WD1772 ourselves to verify the information we had—and to 
discover deviations from this information. 

As a result, this section contains more than enough information for those 
who just want an overview of the controller. This section also contains 
information for programmers who want to know how the FDC works, and 
want to control it directly from their own programs. 

It's not necessary to program the FDC yourself for normal data exchange 
between the disk drive and the ST. Appropriate calls to the BIOS or XBIOS 
will handle this. 

However, the operating system does not support all of the capabilities of the 
FDC. For programmers who want to develop a fast copy program or devise 
some form of copy protection, for example, these missing functions are 
quite important. If you want to create special disk formats, you cannot use 
the existing operating system routine for track formatting—you will have to 
write your own. 

To use these functions in an application program, the controller must be 
programmed directly. This is only possible if you have a good knowledge 
of the FDC commands and the way they work. 

This knowledge can save you hours of programming and debugging, only 
to find out that your idea would never work. An example of such an idea: 


80 



Abacus 


Atari ST Disk Drives Inside and Out 


"If I read all of the tracks of a diskette into the computer with the 
READ TRACK command and then write all of the tracks onto another 
diskette with the WRITE TRACK command, I'd have the fastest copy 
program imaginable. And I could use this to make 'backups' of copy¬ 
protected disks. The READ TRACK command reads all of the information 
on the track (including the copy protection), and the WRITE TRACK 
command will write all of it back out again!" 

If you actually wrote a program that worked this way, however, you would 
find that the copies that it created were unusable—and it wouldn't even copy 
an unprotected diskette. 

After you have worked through this section and know how the FDC 
commands work and what they do, you'll see why the copy program above 
won't work. We are reasonably sure that the description of the controller is 
comprehensive enough to inhibit "ideas" of this sort. 

Now to the description of the WD1772 (finally!). Developed by Western 
Digital, this chip incorporates all of the functions necessary for controlling a 
5 1/4" drive. As the Atari ST demonstrates, the WD1772 can also control 
3 1/2" drives. This capability of the WD1772 comes thanks to Sony, the 
developer of the 3 1/2" drive. Sony decided that a faster market introduction 
would be possible if the 3 1/2" drives were equipped with an interface 
compatible with 5 1/4" drives. From an ST owner's point of view, this 
means that you can also connect 5 1/4" drives to your computer. 

But be careful with older disk drives—especially rebuilt or used 
ones—which can be had for very low prices. If you want to connect this 
type of device as a foreign drive, you may run into problems for the 
following reason: 

The standard version of the WD177x series (the WD1770) is software 
compatible with the older FDC series WD179x and WD279x. But the 
WD1772 uses shorter stepping rates than these other models. The stepping 
rate is the time the controller waits between tracks when moving the 
read/write head across the disk. The four programmable times of the 
WD1772 are 2, 3, 5 and 6 ms, while on the WD1770 they are 6, 12, 20, 
and 30 ms. This means that the drive must be capable of changing tracks in 
a maximum of 6 ms. You should find the stepping rate information in the 
documentation for the drive under "TRACK TO TRACK." 


81 


Abacus 


Atari ST Disk Drives Inside and Out 


Let's look at the FDC now and start with a brief summary of the features of 
this chip: 

• 28-pin Dual-Inline-Package 

• single 5 V supply 

• integral digital data separator 

• integral write precompensation 

• single and double write density 

• integral motor control 

• sector lengths of 128, 256, 512, or 1024 bytes 

• fast stepping rates (2, 3, 5, and 6 ms) 

We want to explain two of these points right now and we'll get to the rest in 
the following sections, in connection with the individual functions of the 
FDC. 

1) The fact that the WD1772 is contained in a 28-pin package is 
important only for the development of a system in which an 
FDC is required. Since a 28-pin chip means less layout work 
than a 40-pin device, system developers are more likely to 
choose devices with fewer pins (assuming the features are 
equivalent). 

2) The ability to operate the WD1772 in single or double density 
will not be treated in the course of the controller discussion. The 
reason for this is simple: In the Atari ST, the FDC is used in 
double-density mode. To use the controller in the single-density 
mode, the computer must be opened and wiring of the FDC 
changed. The result of this undertaking would be that only 50% 
as much information could be stored on a disk as before. 
Although it doesn't seem like there would be any reason to do 
this (after all, why would anyone throw away half the storage 
capacity?), it might be useful to do this in practice to create a 
disk format compatible with some other computer. Special cases 
like this are not of general interest, however. Since the FDC is 
already complicated enough, we won't burden you with 
capabilities which will probably never be used in the ST. 


82 


Abacus 


Atari ST Disk Drives Inside and Out 



83 








Abacus 


Atari ST Disk Drives Inside and Out 


PIN 1 CS (CHIP SELECT) 

A low signal on this input selects the chip and allows access to 
the registers. The CHIP SELECT connection is found on all 
peripheral components including the memory chips. Since they 
are all connected to the data bus of the processor, there has to 
be some way of keeping them from all trying to use the bus at 
once. The CHIP SELECT lines enable just one device for data 
transfer. In the ST, the FDC is selected by the DMA controller. 

PIN 2 RAV (READAVRITE) 

The signal at this input controls the data direction. If it is high, 
the contents of the selected register are output on DAL0-DAL7, 
while if it is low, the data on DAL0-DAL7 is placed in the 
selected register. 


PINS 3,4 A0,A1 (ADDRESS 0,1) 

These two inputs select the FDC register. The WD1772 has 5 
registers which are addressable by the computer system. But 
since two address lines can select only four registers, one 
address has two registers (A0=0 and A 1=0). The signal on the 
RAV pin is used to decide between these two registers. 

CS A1 AO R/W = 1 R/W = 0 


0 0 0 

0 0 1 

0 10 

Oil 


Status reg. 
Track reg. 
Sector reg. 
Data- reg. 


Command reg. 
Track reg. 
Sector reg. 
Data reg. 


The result is that the command register cannot be read and the 
status register cannot be written. 


These pins are connected to the DMA controller and not the 
processor address bus. The FDC registers are selected via a 
control register in the DMA controller. 


PINS 5-12 DAL0-DAL7 (DATA ACCESS LINE 0-7) 

These eight lines make up the bidirectional data bus. The data 
between the computer system and the FDC registers are 
transferred over this bus. These lines, like the address lines, 
are connected to the DMA controller. The FDC registers are 
accessed indirectly via the data registers of the DMA controller, 
which is selected via the control register of the DMA controller. 


84 




Abacus 


Atari ST Disk Drives Inside and Out 


PIN 13 MR (MASTER RESET) 

After power is supplied to the FDC, the contents of its registers 
are purely random and the registers must be placed in a defined 
initial state. This is achieved by a low pulse (of at least 50|is) at 
this input. 

This is usually done after the ST is turned on. Naturally, it is 
always possible to reset the FIX! with the 68000's RESET 
command. But remember, the other devices connected to this 
common line will also be reset if you execute this command. 

PIN 14 GND (GROUND) 

Ground connection. 

PIN 15 Vcc (POWER SUPPLY) 

The +5V supply connection. 

PIN 16 STEP (STEP) 

This output sends a pulse to the drive for each step the 
read/write head is to be moved. 

PIN 17 DIRC (DIRECTION) 

The FDC uses the signal on this line to tell the drive the 
direction in which to the move when it encounters a STEP 
pulse. If this pin is high, a STEP pulse moves the head toward 
the center of the disk, while if it is low, a STEP pulse moves 
the head one track out. 

PIN 18 CLK (CLOCK) 

Like a microprocessor, a command issued to the FDC executes 
microprograms within it. This is why the FDC is supplied with 
a clock, just like a microprocessor, which controls the 
execution. This clock is also required for the timing of the 
serial data stream. 

The clock is not created by the FDC itself but is taken from the 
outside via the CLK input. The clock frequency is 8 MHz. 

PIN 19 RD (READ DATA) 

The signal which the read/write head of the drive sends is 
connected to this input of the FDC. The data separator in the 
FDC separates the clock and data pulses, which are both 
contained in the signal. 


85 



Abacus 


Atari ST Disk Drives Inside and Out 


PIN 20 

PIN 21 

PIN 22 

PIN 23 

PIN 24 

PIN 25 


MO (MOTOR ON) 

This output is used for motor control. The drive motors are 
started by the FDC for read, write, and seek operations. 

WG (WRITE GATE) 

The data pulses which the FDC sends to the drive are first sent 
to a write amplifier instead of directly to the read/write head. If 
no data items are sent by the FDC, the input of this amplifier is 
open. Amplifiers with open inputs have the unpleasant property 
of being sensitive to stray voltages that might enter the 
connection cable. To keep such voltages from reaching the 
read/write head and thereby destroying data on the disk, the 
drives have a circuit which controls the write amplifier. For 
write operations, WRITE GATE is set to a high signal by the 
FDC. This enables the write amplifier, and the data pulses that 
arrive over the WRITE DATA line can be processed. 

WD (WRITE DATA) 

The information to be written to the disk, consisting of data and 
clock pulses, is sent to the drive via this line. 

TR00 (TRACK 00) 

The disk drives have a light barrier which detects when the 
read/write head is over track zero. When the head is over track 
zero, this input of the FDC is set to low. 

IP (INDEX PULSE) 

The drive sends a pulse to this pin on each revolution of the 
disk, which the controller then uses for its operations. For 
example, it uses this signal to detect the start of track when 
reading or writing. 

The speed of the drive motor can also be measured by counting 
the index pulses in a given length of time. 

The index pulse on the 3 1/2" drives is created independent of 
the diskette. 3 1/2" diskettes, unlike 5 1/4" diskettes, do not 
have an index hole. 

WPRT (WRITE PROTECT) 

This input is tested before the FDC attempts a write operation. 
If this input from the drive is placed low (write-protected 
diskette), the controller will terminate the write operation. 


86 




Abacus 


Atari ST Disk Drives Inside and Out 


PIN 26 DDEN (DOUBLE DENSITY ENABLE) 

The signal at this input determines the recording format with 
which the FDC works. A low signal at this pin puts the 
controller in the double-density mode, while a high places it in 
the single-density mode. In the Atari ST the WD1772 is always 
operated in the double-density mode because DDEN is 
connected to ground. 

PIN 27 DRQ (DATA REQUEST) 

This output, the condition of which is indicated by a bit in the 
status register, has the following meaning when it is placed 
high by the FDC: 

a) For a read operation, a byte is in the data register 
which must now be read (data register full). 

b) For a write operation the data register is empty 
and must be filled with the next byte to be 
written. 

Reading or writing the data register resets the DRQ output and 
the DRQ status bit. 

The DMA capability of the WD1772 rests on the existence of 
this output. In the Atari ST, this pin is connected to the DMA 
controller. During read and write operations, the DRQ status bit 
must be read to recognize when a data transfer takes place. The 
DMA controller handles this through the DRQ output. 

PIN 28 INTRQ (INTERRUPT REQUEST) 

After each command, this FDC output is set high. It is reset 
when the status is read. This connection is connected to the I/O 
port (bit 5) of the MFP 68901. To recognize when the FDC has 
finished a command, this port bit is read in a loop. It should be 
noted that this bit is inverted. The command is ended when the 
port bit is cleared. 

It is possible to program the MFP so that a high on the INTRQ 
output generates an interrupt. This saves having to poll the port 
bit continually. The interrupt control is not used by the 
operating system. 


87 




Abacus 


Atari ST Disk Drives Inside and Out 


4.2.2.2 Organization 

To better understand the programming of the FDC, which is explained in 
detail later, it's a good idea to take a look at the function diagram of the 
WD1772 and then talk about the individual function blocks. 


DAL 0-7 



WD1772 organization 


88 




















Abacus 


Atari ST Disk Drives Inside and Out 


Data shift register (DSR) 

During a read operation, the serial data which arrive over the READ DATA 
input (RD) are collected in this 8-bit shift register. For write operations the 
contents of this register are sent out in serial over the WRITE DATA output 
(WD). For some operations the data shift register is also used for temporary 
storage. 

Data register (DR) 

For a read/write operation, this register is used as temporary storage. When 
the DSR has received eight bits after a read operation, this information is 
transferred to the data register. For write operations, the next byte is 
transferred to the DSR after the DSR has sent a byte. 

For a seek operation, the data register contains the number of desired track. 

Track register (TR) 

This register normally contains the track over which the read/write head is 
located—but there are exceptions to this. To keep the track register up to 
date, it is incremented by one for each step in and decremented by one for 
each step out. The commands RESTORE and SEEK increment or 
decrement the register every time. However, this is only true for the 
commands STEP, STEP IN and STEP OUT if the update flag (U bit) is set. 

For write, read, and verify operations, the contents of the track register are 
compared with the track number recorded in the ID field. 

The track register can be read and written, but it should not be loaded during 
an operation. 

Sector register (SR) 

For read and write operations, this register contains the number of the 
desired sector, which is compared with the sector number recorded in the ID 
field. After a READ ADDRESS command, the sector number from the ID 
field is in the register. 

The sector register can be read and written, but it should not be loaded 
during an operation. 


89 




Abacus 


Atari ST Disk Drives Inside and Out 


Command register (CR) 

This register contains the command currently being executed. It can only be 
written because reading automatically selects the status register. The 
command register should not be loaded during an operation, except when 
the command is FORCE INTERRUPT. 

Status register (STR) 

The information found in this register indicates the status of the FDC/drive. 
The individual bits are partially dependent on the command being 
processed. The status register can only be read, whereby the byte read has 
the following meaning(s): 

Bit 7 MOTOR ON 

This bit reflects the status of the MOTOR ON output. It is set 
for about one to two seconds after a command, if the busy bit 
is already cleared. 

Bit 6 WRITE PROTECT 

After write operations, this bit indicates whether or not the 
diskette in the drive is write protected. If it is set, it also 
means that the desired write operation was not executed. The 
WPRT bit is set (in the case of a write-protected diskette) 
after a type 1 command. This bit is reset when an operation 
with a non-write-protected diskette takes place. 

Bit5 SPIN UP/RECORD TYPE 

SPIN UP: For type 1 commands this bit is set at the 
conclusion of the spin up sequence. This shows that the 
drive motor has (probably) reached its nominal rotation rate. 

RECORD TYPE: After a READ SECTOR command, this bit 
indicates whether the data field starts with a "normal" or an 
"erased" data mark. 

Bit 5 = 0, "normal" data mark ($FB) 

Bit 5 = 1, "erased" data mark ($F8) 

Bit 4 RECORD NOT FOUND (RNF) 

If no correct ID field was found, this bit is set. This could be 
the case after a READ SECTOR, WRITE SECTOR, or 
READ ADDRESS command. However, after a READ 


90 




Abacus 


Atari ST Disk Drives Inside and Out 


SECTOR command, the RNF bit can be set despite a correct 
ID field. This is the case if no data mark was found within 
the 43 bytes which follow the last CRC byte in the ID field. 

Bit 3 CRC ERROR 

This bit is set if the contents of the CRC field in the data field 
or the ID field do not match the contents of the CRC register. 

Bit 2 LOST DATA/TRACK 00 

LOST DATA: If no action is taken after a data request 
(indicated by the DRQ output or DRQ status bit) within the 
required time for a type 2 or type 3 command, this bit is set. 

TRACK 00: For type 1 commands this bit is set when the 
read/write head is on track zero. 

Bit 1 DATA REQUEST / INDEX 

DATA REQUEST: This bit is set when data is ready or 
required for type 2 and type 3 commands. It is reset by 
reading or writing the data register. 

INDEX: For type 1 commands this bit is set during an index 
pulse. 

BitO BUSY 

This command is set during the execution of a command. 

CRC Logic 

To avoid read errors, a process must be used that supports high data 
security. The process used here generates 16-bit checksum from the written 
data according to a specific algorithm and this checksum is written after the 
data on the diskette. 

When these data items are read again the checksum is generated again 
according to the same algorithm. If this checksum matches the recorded 
checksum, you can be almost 100 percent certain that the data was read 
correctly. The complicated algorithm makes it highly improbable that the 
checksums would match if there were read errors. 

These 16-bit checksums are called Cyclic Redundancy Checks (CRC). The 
CRC logic is responsible for the creation and control of the checksums. The 


91 


Abacus 


Atari ST Disk Drives Inside and Out 


calculation is performed in hardware to speed the operation up. The 
hardware calculates the sum using the following polynomial: 

CRC(x) = x 16 + x 12 + x 5 + 1. 

Arithmetic Logic Unit (ALU) 

The ALU is used for register modification (increment, decrement). The 
ALU is also used for comparisons between registers and the information 
contained on the disk in the ID fields. 

Address Mark Detector 

This detector is probably the most important part of the FDC. As its name 
indicates, this part is capable of recognizing an address mark. This mark 
designates the start of an ID field (index address mark) or the start of a data 
field (data address mark). 

But why do we need a special detector? As an example, let's take the value 
$FE. The controller interprets this value as an index address mark. Even 
without a special detector it isn't difficult to find this $FE. However, the 
problem becomes clear when we consider that this value can occur in a data 
field, where it must not be evaluated as an index address mark. How is it 
possible to distinguish one $FE from the other $FE? The address mark 
detector takes care of this for us. 

As we mentioned before, the recorded information consists of more than 
just data pulses—clock pulses are also found in it. For read operations these 
are filtered out of the signal by the data separator and sent to the address 
mark detector. 

For a WRITE TRACK command, values which are larger than $F4 require 
special handling. The common feature of these values is that they are written 
without clock pulses. Values written like this consist only of data pulses. 
When this information is read, no clock pulses will arrive from the data 
separator because none are present in the signal. The address mark detector 
is activated by the absence of clock pulses. It can only recognize an address 
mark when it is written without clock pulses. 

There is another problem, however. This one you probably didn't know 
anything about, because we have always talked about "complete" data 
bytes. These bytes are recorded in serial, but the start of a byte is not 
marked in any way. When eight bits are collected in the DSR by a read 


92 



Abacus 


Atari ST Disk Drives Inside and Out 


operation, we can't just assume that they belong to a single data byte. They 
could just as well be four bits from each of two different data bytes. 

The address mark detector will recognize an address mark only if the 
collection of data bytes happens to be byte-synchronized. It's easy to see 
that we can't leave this up to chance—there has to be a way of recognizing 
the start of a byte. This is done through the synchronization byte. These are 
written (three of them) before each address mark when formatting a track. 
The SYNC bytes, like the address marks, don't contain any clock pulses, 
and therefore they activate the address mark detector. 

The controller, informed of the status of the address mark detector, reads 
the serial data bits until the contents of the DSR correspond to a SYNC 
byte. After this, the next bit must be the first bit of the following byte. 

One thing should be noted, however. The bytes read can be corrupted while 
the detector is enabled (see the READ TRACK command). When and why 
are the bytes corrupted? If the detector is activated by missing clock pulses, 
the FDC assumes that SYNC bytes and an address mark follow. In the 
synchronization phase (following the reconstruction of a SYNC byte), some 
of the data bits are discarded. If the detector "accidentally" trespasses on a 
data field looking for an address mark, the data up to the time the "false 
alarm" is recognized and changed. Since the address mark detector is so 
sensitive, it overreacts to missing clock pulses, and is switched off when ID 
or data fields are being read. 

Data Separator 

The data separator was actually described along with the address mark 
detector. We will mention here again that the data separator's job is to 
remove the clock pulses from the signal read and to send them to the 
address mark detector. 

The interface to the computer system 

The processor interface consists of eight bi-directional data lines 
(DAL0-DAL7), the two address lines (AO, Al), the data request (DRQ), the 
interrupt request (INTRQ), the chip select (CS), the read/write line (R/W), 
the clock input (CLK), and the master reset input (MR). These connections 
carry the exchange of data and control signals between the processor and the 
FDC. 


93 



Abacus 


Atari ST Disk Drives Inside and Out 


The interface to the drive 

The controller receives the following information: 

1) whether a write-protected diskette is inserted (WPRT=1) 

2) whether the read)write head is over track 0 (TR00=0) 

3) whether the diskette completed a 360° revolution (IP=0) 

4) the serial data that was read 

The signals which the controller sends to the drive are: 

1) turn the drive motor on (MOTOR ON = 1) 

2) step the read/write head (STEP= 1) 

3) the direction of the step (DIRC=0 or 1) 

4) turn on the write logic (WG=1) 

5) the serial data to be written (WD) 


Process control 

When a command is performed by the FDC, the individual functions must 
be turned on and off in a certain order. Moreover, data items are transferred 
between the FDC registers, calculations are made, input lines are read, and 
output line status is changed. The entire process, depending on the 
command, is controlled or supervised by the process control. 

Read operations 

Read operations generally take place only as a result of the READ SECTOR 
command. The other commands, which can also be used to read data from 
the diskette, are used only for diagnostic purposes and have no meaning for 
normal operation. 

The sectors can be 128, 256, 512, or 1024 bytes long. The sector length is 
determined at formatting by the length field (the fourth byte in the ID field). 

When a sector is to be read, the controller uses the length field to figure out 
how many bytes must be after the data address mark. An precondition for 
error-free reading of the data byte is that the address mark detector is turned 
off during this time. Otherwise it may create read errors. 


94 


Abacus 


Atari ST Disk Drives Inside and Out 


Write operations 

Before data can be written to the diskette with a write command, the WRITE 
GATE output of the FIX! must be activated. As protection against accidental 
writing, this is not done until the data register is loaded as a reaction to the 
DRQ output set by the FDC. 

If this is not done, the command execution is completed, INTRQ is set, the 
LOST DATA status bit set, and the BUSY status bit is cleared. If a reaction 
is made to the first data request, the write command will be executed. If the 
FDC does not transfer another data in response to a subsequent data 
request, the command will not be terminated and a "zero-byte" is written 
instead. The LOST DATA bit is also set after the command is completed. If 
only 112 bytes were transferred by a WRITE SECTOR command, the 
controller would fill the remaining 400 bytes with zeroes (assuming a sector 
size of 512 bytes). 

This should not be used to erase part of a sector. Since the LOST DATA bit 
is set in any event, there is no way to tell if an error occurred when writing 
actual data or not. 

Writing is usually suppressed when the WRITE PROTECT input is marked 
low. In this case, any write command is terminated immediately, INTRQ is 
placed high, the WRITE PROTECT status bit set, and the BUSY status bit 
cleared. 

To increase the data security when the write density increases (on the inner 
tracks), it is possible to enable what is called write precompensation. If the 
write pre com pensation bit is cleared in the write command, the data stream 
over WRITE DATA is sent 125 nanoseconds earlier or later, depending on 
the bit pattern to be written. The following table shows the cases: 

X 1 1 0 earlier 

X 0 1 1 later 

0 0 0 1 earlier 

1 0 0 0 later 

I I I I 

I I I I_next bit to be transferred 

I I I_bit currently being sent 

I_I_ previously transferred bit 


95 




Abacus 


Atari ST Disk Drives Inside and Out 


The write precompensation is normally enabled on the inner tracks of 5 1/4" 
diskettes, where the write density is the highest. The precompensation is 
usually constantly enabled for 3 1/2" diskettes—the data density on their 
outer tracks already reaches the density of the middle tracks on a 5 1/4" 
diskette. 


4.2.2.3 Command description 

Now that we have seen the internal construction of the FDC and gone into 
some of the basic processes involved in read and write operations, we will 
talk about the commands. 

The WD1772 recognizes eleven commands, and these are divided into four 
groups or types. The following table gives an overview of the commands: 


Type 

Command 

Bit 

7 

6 

5 

4 

3 

2 

1 

0 

I 

Restore 

0 

0 

0 

0 

h 

V 

rl 

rO 

I 

Seek 

0 

0 

0 

1 

h 

V 

rl 

rO 

I 

Step 

0 

0 

1 

u 

h 

V 

rl 

rO 

I 

Step in 

0 

1 

0 

u 

h 

V 

rl 

rO 

I 

Step out 

0 

1 

1 

u 

h 

V 

rl 

rO 

II 

Read sector 

1 

0 

0 

m 

h 

E 

0 

0 

II 

Write sector 

1 

0 

1 

m 

h 

E 

P 

aO 

III 

Read address 

1 

1 

0 

0 

h 

E 

0 

0 

III 

Read track 

1 

1 

1 

0 

h 

E 

P 

aO 

III 

Write track 

1 

1 

1 

1 

h 

E 

P 

0 

IV 

Force interrupt 

1 

1 

0 

1 

13 

12 

12 

10 


These commands have several flag bits which have the following meanings: 

h = Motor On Flag h = 0, enable motor-on test 

h = 1, disable motor-on test 

When the drive motor is switched on, the operating system should delay 
until the motor has reached its operating speed. The WD1772 accomplishes 
this delay by waiting 6 index pulses after the motor is turned on. With an 
operating speed of 300 RPM, this delay time is at least one second. This 


96 



Abacus 


Atari ST Disk Drives Inside and Out 


process, called the spin-up sequence, ensures that the motors have reached 
their required speed by the time the read/write operations take place. 

After ending a command, the drive motors will not be turned off until ten 
more disk rotations are counted (about 2 seconds). If another command 
occurs during this time, it would be just a waste of time to go through 
another spin-up sequence. This is why a motor-on test was implemented in 
the controller. If this test is enabled (h=0), the MOTOR ON output will first 
be tested. If it is low, the FDC goes through the spin-up sequence. If 
MOTOR ON is high, however, the controller assumes that the motors are at 
their operating speed and continues processing the command. 

If the FDC receives a command (with the h-bit set), it first turns on the drive 
motors by placing MOTOR ON high. This is regardless of whether the 
MOTOR ON output is high already or not. It then begins executing the 
command immediately and does not wait until six index pulses have been 
received. 

V = verify flag V = 0, disable verify 

V = 1, enable verify 

This flag bit exists only in type-I commands. If it is set, the controller 
performs a track verification after a step command or after the last step in a 
restore or seek command. It does this by searching for a correct ID field 
after the step, whose track number matches the contents of the track 
register. 

Whether or not a verify is executed should be determined by the subsequent 
command, because a verify is not necessarily required and not always 
sensible. 

If a READ or WRITE SECTOR command follows and the read/write head 
is not on the desired track, an incorrect sector will never be written or read 
because these commands executed a verify. 

A verify doesn't make sense in certain situations, such as when a new 
diskette is being formatted. The verify after each STEP command would be 
negative. Since the controller searches for a correct ID field for the time of 
five revolutions, about one minute would be wasted while formatting the 
diskette. 

If you format a single track on a diskette that already contains data, use a 
verify to be safe. The WRITE TRACK command, which is used for 


97 



Abacus 


Atari ST Disk Drives Inside and Out 


formatting, does not perform any tests on the track before it is executed. 
The track over which the read/write head is positioned is formatted. 

rl, rO = stepping rate 0 0 2ms 

0 1 3ms 

1 0 5ms 

1 1 6ms 

The step rate of the drives can be programmed with these two bits. This is 
the delay time between the individual step pulses for a SEEK or RESTORE 
command. This feature is used to adapt the FDC to the physical limitations 
of the drive. 

As an example let's take a drive whose head mechanism requires 6ms per 
step. If the step rate is set to 3ms and the head is moved with a SEEK 
command from track 0 to track 40 (which corresponds to 39 step pulses), 
the head would only reach track 20—every other pulse would be lost due to 
the mechanical limits. 

The drive will probably be correctly controlled by individual step pulses 
(STEP, STEP IN, STEP OUT) because the duration of the step pulse is not 
affected by the stepping rate. This pulse is determined by the internal timing 
of the FDC and is about 4|is long. 

u = update flag u = 0, do not update track register 

u = 1, update track register 

If the u-bit is set for a STEP, STEP IN, or STEP OUT command, the track 
register is incremented or decremented by one, as appropriate, after the 
operation. This does not mean that the contents of the track register match 
the actual track. Two conditions must be met for this to happen: 

1) The actual track number must have matched the contents of the 
track register before the step. 

2) No attempt can be made to access a track number greater than 
82. If the read/write head is on track 82 (the last track the drive 
can reach), for example, the track register would contain the 
number 87 after five STEP IN commands, while the head would 
stay at track 82. 


98 




Abacus 


Atari ST Disk Drives Inside and Out 


m = multiple sector m = 0, read or write one sector 

m = 1, read or write multiple sectors 

This bit lets you read or write a maximum of all of the sectors on a track at 
once. It is assumed that the sector numbers are in a continuous sequence. 
The number of the first sector to be read or written is written to the sector 
register beforehand. After the FDC has read/written this sector, it 
increments the sector register and attempts to read/write the next sector. This 
continues until no more sectors are found or the command is terminated 
with a FORCE INTERRUPT command. 

aO = data address mark aO = 0, write normal data mark ($FB) 

aO = 1, write erased data mark ($F8) 

The data address mark designates the start of the data field. The capability to 
write different data address marks with the aO bit (depending on whether it 
is set or cleared) allows you to easily mark a sector. The type of data 
address mark is indicated in the RECORD TYPE status bit after a READ 
SECTOR command. 

E = 30ms settling delay E = 0, no head settling time 

E = 1, 30ms head settling time 

Some drives have read/write heads that are not constantly in contact with the 
magnetic disk surface. These drives raise or lower the head with a solenoid. 
This setup, called head load, is intended to reduce the wear and tear on the 
diskette by lowering the head only when read or write operations are 
actually taking place. Lowering the head causes vibrations in the head 
mechanism, which prevents optimum contact between the head and the 
storage medium for a given length of time. Setting the E-bit results in a 
delay that takes this settling time into account. 

P = write precompensation P = 0, enable write precompensation 

P = 1, disable write precompensation 

10-13 = interrupt conditions 10 = 1, no meaning 

11 = 1, no meaning 

12 = 1, interrupt on next index pulse 

13 = 1, immediate interrupt 

10-13 = 0, terminate current command 
without interrupt 


99 




Abacus 


Atari ST Disk Drives Inside and Out 


The type-I commands 

The type-II and type-III commands, which are responsible for reading and 
writing data, always refer to the track that the read/write head is located over 
at the time. The group of commands consisting of RESTORE, SEEK, 
STEP, STEP IN, and STEP OUT is responsible for positioning the head. 

RESTORE (seek TRACK 0) 

Command word: 7 6543210 


0 0 0 0 h V rl rO 

When the FDC is sent this command, it first tests the TROO input. If the 
TR00 input is low (because the read/write is already over track 0), the track 
register will simply be set to zero. 

If the read/write is not over track 0, STEP OUT pulses will be created until 
the TROO input goes low. If this is not the case after 255 step pulses, the 
command is terminated. The end of the command is indicated by the setting 
of the INTRQ output and the clearing of the BUSY status bit. 

SEEK 

Command word: 76543210 


0 0 0 1 h V rl rO 

This command moves the read/write head directly over a given track. The 
number of the desired track is first written to the data register. For this 
command to work properly, the contents of the track register must be the 
current track number. If more than one drive is used, the track register may 
have to be loaded so that it points to the current track number. 

When the FDC receives a SEEK command, it compares the track register 
with the data register, which tells it whether a STEP IN or STEP OUT is 
necessary. Step pulses are then generated for the appropriate direction. The 
track register is UPDATEd after each step pulse. Once the contents of the 
track register and the data register are equal, the destination track has been 
reached and the command is ended. This is indicated by setting the INTRQ 
output and clearing the BUSY status bit. 


100 





Abacus 


Atari ST Disk Drives Inside and Out 


STEP 

Command word: 76543210 


0 0 1 u h V rl rO 

This command causes the FDC to output a step pulse. The direction is the 
same as that used for a previous step pulse, because the state of the 
DIRECTION output is not changed. The INTRQ output is set high 
afterwards, and the BUSY status bit is cleared. 

STEP IN 

Command word: 76543210 


0 1 0 u h V rl rO 

A STEP IN command sets the DIRECTION output to high, regardless of 
what it was before, and sends out a step pulse. This moves the read/write 
head one step toward the center of the disk. The INTRQ output is set high 
and the BUSY status bit cleared. 

STEP OUT 

Command word: 76543210 


0 1 1 u h V rl rO 

A STEP OUT command sets the DIRECTION output to low, regardless of 
what it was before, and sends out a step pulse. This moves the read/write 
head one step toward the edge of the disk. The INTRQ output is set high 
and the BUSY status bit cleared. 

The verify sequence for type-I commands 

If the V-bit is set in a command, the following sequence is executed when 
the desired track is reached and after a 30 millisecond delay: 

The track number from the first ID field read is compared with the contents 
of the track register. If they match, the CRC byte of the ID field is tested. If 
this matches the byte generated by the CRC logic, the verify sequence is 
terminated without error. The INTRQ output is placed high and the BUSY 
status bit is cleared. 


101 







Abacus 


Atari ST Disk Drives Inside and Out 


If either the track number or the CRC checksum in the ID field is wrong, the 
next ID field is read and a new test made. If an ID field with the correct 
track number and valid checksum is not found within five revolutions, the 
RECORD NOT FOUND bit is set in the status register. The command 
terminates, as indicated by the set INTRQ ouput and the cleared BUSY 
status bit. 


Flow chart of the type-I commands 

To clarify the operation of the type-I commands, here are some flowcharts 
which demonstrate the processes: 



102 















Abacus 


Atari ST Disk Drives Inside and Out 



103 
















Abacus 


Atari ST Disk Drives Inside and Out 



Flowchart for 
Type-1 commands 


/ is the^\ 
VERIFY flag 
. set 


30 ms delay 
(head resting time) 



set INTRO 
clear BUSY 
set RNF 


/ have s 
6 index impulses 
'^.occurred 

1NO 


has an^v^ 
ID address marx 
\been founc^-' 


^ns TRs'v, 
track number 
s ^in ID array 


clear CRC 


set INTRQ 
clear BUSY 


was the^ 
CRC array 
correct 


set CRC error 


104 










Abacus 


Atari ST Disk Drives Inside and Out 


The Type II commands 

This group of commands is responsible for reading and writing sectors, 
which are the logical data units. Data exchange is carried out exclusively 
with these commands. 

Like all commands which read and write information, these also work 
relative to the track over which the read/write head is currently located. 

READ SECTOR 

Command word:7 6543210 


lOOmhEOO 

The FDC is given the number of the sector to be read in the sector register. 
When a READ SECTOR command is then started, the controller reads an 
ID field and tests to see if its track and sector numbers match the contents of 
the track and sector registers. If this is not the case, the next ID field is read. 

If they were the same, the sector length is saved and the CRC checksum of 
the ID field is compared with the one calculated from the data read. If these 
are the same, then the ID field belonging to the desired sector has been 
found. Otherwise another ID field is read. 

Before the data field can be read, a data address mark (DAM) must be found 
in the next 43 bytes. If a DAM is not found, another ID field is read. 

If no matching ID field is found after five revolutions, or a DAM did not 
follow in the 43 bytes after it, the RNF status bit is set and the command 
terminated. 

As you can see, certain conditions must be fulfilled before the FDC reads a 
data field containing a sector. If everything has gone smoothly up to now, 
then the process continues as follows: 

The type of data address mark (normal=0, erased=l) is indicated in status 
bit 5. The address mark detector is disabled and the appropriate number of 
data bytes (calculated from the specification in the sector-length field) is 
read. A DRQ is generated for each byte read. If no reaction is made to this 
DRQ, the FDC sets the LOST DATA status bit 


105 





Abacus 


Atari ST Disk Drives Inside and Out 


After all of the data bytes have been read, a CRC checksum is tested again. 
This is located in the two bytes following the sector and is compared with 
the checksum calculated from the sector data. If the two do not match, the 
CRC error status bit is set. 

The end of the operation is indicated by setting the DRQ output and clearing 
the BUSY status bit. 

READ SECTOR (with m-bit set) 

If the m-bit is set in the command word of the READ SECTOR command, 
the FDC tries to read multiple sectors (up to one track). The number of the 
first sector to be read is passed to the controller in the sector register. The 
operation of the command is first identical to the one described above. After 
the sector has been read, however, the controller automatically increments 
the sector register and starts another READ SECTOR. 

This continues until no more sectors are found. In other words, this 
command is always terminated with a RECORD NOT FOUND error. 

Since we can't tell the controller how many sectors to read, there has to be 
some other way to read multiple sectors. This is where the FORCE 
INTERRUPT command comes in. We don't wait until the FDC finishes the 
command itself, but instead we determine when we're done. 

Here is an example of how we might do this: 

Let's assume the following: The read/write head is positioned over an 
Atari-formatted track. The sectors of this track are numbered 1-9. We want 
to read the five sectors from 3-7. The sector number is passed to the sector 
register, and the read operation is started by passing the command word. 

If nothing else happens, seven sectors are read (3-9) and the command is 
terminated after five rotations with an RNF error (because sector 10 could 
not be found). 

But we want to read just sectors 3-7 (and we don't want an error message). 
This is how we do it: 

Since the data transfer is handled by the DMA controller, it is initialized with 
a DMA start address before the FDC command is started. This address is 
continually incremented as the FDC passes the data to the DMA controller. 
Therefore the current DMA address can be determined by reading the DMA 


106 


Abacus 


Atari ST Disk Drives Inside and Out 


address register. This register is continually read until its contents are 
incremented beyond $A00 (5*$200), the start address. When this is the 
case, the READ SECTOR command is terminated with a FORCE 
INTERRUPT command. 

WRITE SECTOR 

Command word: 76543210 


lOlmhEPaO 

Here we’ll just explain the differences from the READ SECTOR command, 
since much of the operation is the same. 

At the beginning of the command, the FDC checks to see if the WRITE 
PROTECT input is low. If this is the case (write-protected diskette), the 
WPRT status bit is set and the command is terminated. If the disk is not 
write-protected, the ED field search starts. 

If the matching ID field is found, a delay corresponding to 23 bytes is 
made. After this, 12 zero bytes and a data address mark are written (type 
depending on aO). Following this is the actual sector information, followed 
by the CRC checksum. Finally, an $FF byte is written. 

Whether the sector was written correctly or not can only be determined by a 
READ SECTOR command. 

WRITE SECTOR (with m-bit set) 

See the discussion of the READ SECTOR command with m-bit set. 


107 



Abacus 


Atari ST Disk Drives Inside and Out 


Flowcharts of the Type II commands 

We also have flowcharts for the Type II commands. 


( START ) 

I 


Set BUSY 


clear CRC.RNF.DRQ, 
INTRQ, RECORD TYPE 
and LOST DATA 


Flowchart for 
Type-ll commands 


Is the 
MOTOR ON 


YES 


Is 


YES 


s^option 

set? 


NO 

r 

| NO 

Set MOTOR ON 


Set MOTOR ON -wait 
for 6 index impulses 



^_-_ 

v~ 



r 


30 ms delay (head 

Ml 

resting time) 

NX 



clear 

BUSY 


set 

set 

WPRT 

INTRQ 




108 









Abacus 


Atari ST Disk Drives Inside and Out 



>9 









Abacus 


Atari ST Disk Drives Inside and Out 



110 












Abacus 


Atari ST Disk Drives Inside and Out 



111 










Abacus 


Atari ST Disk Drives Inside and Out 


The Type III commands 

The WRITE TRACK command is used for formatting a track. The READ 
TRACK and READ ADDRESS commands are used to analyze track format. 

READ ADDRESS 

Command word:7 6543210 


llOOhEOO 

Here we give you a few warnings about the DMA controller. Programming 
the READ ADDRESS command can easily drive a person crazy! 

After the READ ADDRESS command is started and executed, you might be 
surprised to discover that the ID field is not in RAM. A test of the status 
registers (DMA and FDC) show that no errors occurred. If you subtract the 
start DMA address from the end DMA address, the difference is zero. As a 
result, zero bytes were transferred—fewer than we had hoped. What 
happened to the six-byte ID field? That's easy—it's in the DMA controller! 

The DMA controller does not transfer bytes individually. It waits until it has 
received 16. Not until then does it request the bus from the 68000 processor 
to transfer these 16 bytes into RAM. 

Now, you might ask, how do we get the ID field out of the DMA 
controller? There's only one way to do it: read more data. This is done by 
reading several ID fields in succession. After three READ ADDRESS 
commands (18 bytes), we get 16 bytes in RAM and two in the DMA 
controller. To get all of the bytes transferred from the DMA controller to 
RAM, we have to read a number of byte which is evenly divisible by 16. 

But there's another problem. This results from clearing the DMA status 
register, which is done by toggling the read/write line. If we reset this 
register before each DMA transfer, "just to be safe," we get the second 
surprise. This erases not only the status register, but all of the bytes still in 
the controller. In this case we can read ID fields until the disk falls apart, 
and the DMA controller wouldn't transfer a single byte into memory. 

The moral of the story is that the DMA status register may be 
cleared only before the first READ ADDRESS command. 


112 



Abacus 


Atari ST Disk Drives Inside and Out 


Now on to the READ ADDRESS command itself. 

The READ ADDRESS command causes the next ID field which the 
read/write head encounters to be read. It can be used in connection with the 
READ TRACK command to analyze the format of a disk. Moreover, it is 
also possible to verify a track without leaving it. 

The READ ADDRESS command reads an ID field without testing to see if a 
matching data field exists. Six bytes are read. They have the following 
meanings: 


Bvte # M ea n in g 

1 Track number 

2 Side number 

3 Sector number 

4 Sector size 

5 CRC byte 1 

6 CRC byte 2 

The track number (byte 1) is also written in the sector register. This can be 
used to do a track verify without using the data read. At first, this may seem 
unnecessary, because it doesn't matter if (for a track verify) we compare the 
contents of the sector register, or the first byte to the contents of the track 
register. In addition, it is simpler to use the transferred byte because we 
don't have to select the sector register first to use it. 

As we said before, no information is transferred to RAM until the DMA 
controller has accrued 16 bytes. But since the FDC also writes the first byte 
of the ID field in the sector register, it is still possible to execute a track 
verify with a single READ ADDRESS command. 

If no ID field is found within six index pulses (which corresponds to at least 
five rotations), the RNF status bit is set (RECORD NOT FOUND). Once 
the FDC has finished the command, it sets the INTRQ output and clears the 
BUSY status bit. 

READ TRACK 

Command word: 76543210 


lllOhEOO 


113 



Abacus 


Atari ST Disk Drives Inside and Out 


The READ TRACK command is also used only for track diagnosis. It reads 
a complete track, including all GAP, SYNC, and data bytes. The reading 
begins on the rising edge of the next index pulse which the controller 
receives from the drive. Data is read until another index pulse reaches the 
controller. As usual, the end of the operation is indicated by setting the 
INTRQ output and clearing the BUSY status bit. 

A DRQ is created for each byte read. As with all commands, the LOST 
DATA status bit is set if there is no reaction to the DRQ. Regarding the 
LOST DATA bit, we found that it would sometimes be set for no apparent 
reason. The reason is that this bit doesn't really give information about 
whether data was lost or not after a READ TRACK command. Curiously, 
these cases never occurred for READ TRACK attempts on an unformatted 
disk. 

The "collection" of data bits is synchronized with each received address 
mark. The address mark detector, which is responsible for this, is not 
turned off (as it is for a READ SECTOR command, for instance) but 
remains active during the entire reading process. It is constantly on the 
lookout for an address mark, and therefore creates read errors. 

According to manufacturer specifications, all information can be read 
correctly (with the exception of the GAP bytes). Our attempts had different 
results. In practice, it seems that only the ID fields can be read properly. But 
read errors can even occur at the checksum of the ID field. 

You may wonder where the READ TRACK command can actually be used. 
The data themselves are of dubious value because of possible read errors; 
the READ ADDRESS command is much easier to use for reading ID fields, 
because the ED field search in the track information raises another problem. 
If we have a byte sequence of FE-01-00-01-02-BC-DB, for instance, we 
can’t tell whether it is actually an ID field or not. This byte sequence could 
also occur in a data field. A "real" ID field is simply an ID field that the 
controller recognizes as an ID field. 

Used by itself, the READ TRACK command is not very useful. However, 
when used in conjunction with the READ ADDRESS command, a track 
may be analyzed fairly precisely. Even if the data themselves don't say 
much, the number of data present is of great importance. The distances 
between given points can be measured, which is very important for track 
analysis. This makes up for a disadvantage of READ ADDRESS, which 
reads only ID fields and doesn't test whether a corresponding data field 
exists. 


114 



Abacus 


Atari ST Disk Drives Inside and Out 


As an example, we'll describe how a track analysis would work: 

1) All ID fields on the track are read with READ ADDRESS 
commands. 

2) All track information is read with a READ TRACK command. 

3) All sectors on the track (track and sector numbers are obtained 
from the ID fields) are read with READ SECTOR commands. 

Our analysis is complete if there are no ID fields in the track, because the 
format is unreadable. 

We search for the first ID field in the track information. Here we have to 
orient ourselves by "landmark" points. The first of these points is the byte 
sequence $A1, $1% (or $C2, $FE), which is made up of the SYNC byte 
and the ID address mark. An ID field can follow only a byte sequence like 
this. Once it is found, the second landmark becomes interesting. This is 
located a maximum of 42 bytes behind the ID field. We must find a SYNC 
byte followed by a data address mark. If we don't find a SYNC byte, then 
there is no valid data field for the ID field. 

Another test checks the plausibility of the ID field. For example, if this 
indicates a sector size of 512 bytes, and the next ID field follows at a 
distance of 200 bytes, then something is wrong. 

We read the sectors for two reasons. First, the sector information cannot be 
taken from the data obtained from READ TRACK. Second, the only way to 
check the CRC checksum of a data field is with READ SECTOR. 

WRITE TRACK (FORMAT TRACK) 

Command word: 76543210 


lOOmhEOO 

A diskette must be formatted before it can be used for data storage. But 
what actually happens when we format a disk? 

The sector is the logical data unit used for data transfer between the drive 
and controller is. Since a fresh blank diskette contains no information about 
the start of a sector, it must be assigned starting points before it can be used. 


115 





Abacus 


Atari ST Disk Drives Inside and Out 


Every sector has a field that contains information about the sector. A 
checksum for the data must be also written to a blank disk. Synchronization 
bytes are also missing. These are very important for finding the start of a 
byte which is hidden somewhere in the serial bit stream from a later read 
operation. 

The purpose of formatting is to write all of this information or marks on the 
diskette. This must be done according to certain rules, however, or sector 
transfer is impossible later. If one stays within these rules, a number of 
nonstandard but usable formats can be created. 

The FDC is passed a data byte, a value between $00 and $FF. But to write 
the marks, which differ from the "normal" data, on the disk, it must be 
possible to operate the controller so that a mark is written to the disk instead 
of a data byte. 

First we'll look at the control bytes, which are represented by values $F5 
and $FF. In contrast to the READ SECTOR and WRITE SECTOR 
commands, which write these values as "normal" data bytes, the controller 
can be used to write special marks to the disk with a WRITE TRACK 
command. The common bond for all of these is that they are written without 
clock pulses and can thereby be distinguished from data bytes which the 
same values (see address mark detector). The following table shows what 
effect these control bytes have when they are encountered by later read 
operations: 


Byte given to 

Byte written 


the FDC 

from the FDC 

Meaning 

$F5 

$A1 

Sync-byte, CRC-reg. cleared 

$F6 

$C2 

Sync-byte 

$f7 

$XX,$XX 

2 CRC-bytes 

$F8 

$F8 

'cleared' data address mark 

$F9 

$F9 

Data mark 

$FA 

$FA 

Data mark 

$FB 

$FB 

'normal' data address mark 

$FC 

$FC 

Data mark 

$FD 

$FD 

Data mark 

$FE 

$FE 

Index address mark 

$FF 

$FF 



These control bytes can be used to create different formats. We use some 
examples for creating the ST disk format to help explain how this is done. 
At the appropriate places we'll point out which elements can be changed. 


116 




Abacus 


Atari ST Disk Drives Inside and Out 


Let's start with a buffer that can hold all of the information which is written 
to the diskette by the WRITE TRACK command. This buffer must be at 
least 6250 bytes long. Now we have to fill the buffer so it will correspond 
to a format that can store nine sectors of 512 bytes each. 

If we divide our buffer into two components, we get the following setup, 
which is valid for all formats. Differences in the number of records are 
possible, of course. 

GAPl RECORD 1 RECORD 2 RECORD 9 GAP 5 

A track starts and ends with a block called a GAP. As we'll see later, these 
GAPs are also present in the RECORDS. A GAP is a blank space that 
separates the individual components in the track. It contains no useful 
information, just fill bytes or, if the GAP comes before an ID field or a data 
field, SYNC bytes as well. The FDC is given a length of time 
corresponding to the length of the GAP to prepare itself for the requirements 
of the next component. 




Gap length 

Gap length 

Identifer 

Value 

ATARI format 

Foreign format 

GAPl (track leader) 

$4E 

60 bytes 

min. 32 bytes 

GAP5 (track end) 

$4E 

ca.664 bytes 

min. 16 bytes 


The length of GAP5 is irrelevant at the moment. Simply put, GAP5 is just 
what is left over on the disk. For calculations of the buffer length, we have 
to leave at least 16 bytes for GAP5. 

If we subtract the number of bytes we reserve for GAPl from our buffer, 
we have 6190 bytes available to divided up among the records. But we can't 
do this yet—we don't know the length of a record. 

As you probably guessed by now, each record contains one of our nine 
sectors. So we know one thing for certain: the record length must be larger 
than the sector length. If we take a closer look at a record, we get the 
following picture: 

GAP 2 INDEX-FIELD GAP 3 DATA-FIELD GAP 4 


117 




Abacus 


Atari ST Disk Drives Inside and Out 


First we see the GAPs. In the order they are given above, these GAPs are 
called pre-record, inter-record, and post-record, gaps. 





Gap length 

Gap length 

Identifcr. 


Value 

ATARI format 

Foreign format 

GAP2 


$00 

12 bytes 

min. 8 bytes 


SYNC 

$F5 

3 bytes 

3 bytes 

GAP3 


$4E 

22bytes 

22 bytes 



$00 

12 bytes 

12 bytes 


SYNC 

$F5 

3 bytes 

3 bytes 

GAP4 


$4E 

40 byte 

min. 24 bytes 


Total of GAP-bytes per RECORD 92 byte min. 72 bytes 

The synchronization bytes ($F5) in GAP2 and GAP3 ensure that the 
reading of the serial data bytes is synchronized with the start of the byte. 
Also, they alert the FDC to look for a following address mark and initialize 
the CRC logic. To write a SYNC, the FDC is passed the value $F5, which 
writes an $A1 byte without clock pulses. 

The data Held 

Now that we know about the GAPs found within a RECORD, let's take a 
closer look at the data field in which our sector is found. 

DAM Sector CRD 

$FB 512 data bytes $F7 

The data field starts with the data address mark, which designates the start 
of the sector. The value $FB is interpreted as a "normal" data address mark 
by a later READ SECTOR command, while the value $F8, which can be 
used instead of $FB, is viewed as an "erased" DAM. 

The sector field is filled with "dummy bytes" when formatting. The values 
can be almost anything, but they should never be larger than $F4. There can 
be 128, 256, 512, or 1024 bytes. The FDC uses the index field to determine 
the number of bytes in the sector. 

Passing the value $F7 to the FDC causes it to write the contents of its 16-bit 
CRC register, which contains a checksum, to the disk. Although only one 
byte is passed, the controller still writes two bytes. 


118 




Abacus 


Atari ST Disk Drives Inside and Out 


The total length of the data field for a sector length of 512 bytes, in our 
example, is 515 bytes. 

The index field 

The index field, also called the ID field, contains information about the data 
field which follows it. 

ID-AM Track Side Sector Length CRC 

$FE 00-79 00-01 00-09 00-03 $F7 

The index address mark (ID-AM) is the start mark of the ID field. If the 
controller encounters an ID-AM during a later read operation, it reads the 
next six bytes with its address mark detector turned off. The ID-AM is 
written without clock pulses. 

The three bytes which follow the ID-AM describe the RECORDS. The first 
specification is the track number on which the ID field is located. In our 
case this is a value between 0 and 79, depending on which track is being 
formatted. The side field specifies whether the record is on the front or back 
of the diskette. The byte is not used by the controller for any operations. 
The sector field contains the number of the sector (1-9). 

Since the FDC distinguishes between different sector sizes, it must be told 
how many data bytes are contained in the following sector. This is done by 
the length field. 


Table of sector lengths 

Length field Bytes per sector 
00 128 

01 256 

02 512 

03 1024 

For a sector size of 512 bytes, this field contains "02". 

All that's missing is the checksum. As in the data field, this sum is written 
by passing the value $F7. Adding the lengths of all these values gives a total 
length of seven bytes for an ID field. 

Now that we have looked at all of the components in the track an then- 
order, we can calculate the length of a record. 


119 



Abacus 


Atari ST Disk Drives Inside and Out 


Data field 515 bytes 

ED field + 7 bytes 

GAP2-GAP4 + 92 bytes 

Record length =614 bytes 

This is the actual size of the record. In our buffer a record is only 612 bytes 
long because only one byte is passed to the FDC to write each of the two 
checksums. If one record requires 614 bytes, then we for a track we need 9 
* 614 bytes = 5526 bytes. If we subtract this from the 6190 available bytes, 
we have 644 bytes left over for the track trailer (GAP5). This is more than 
enough since only 16 bytes are actually required here. Even a format which 
uses ten sectors at 512 bytes each would leave 50 bytes for GAP5. 

Let's look at the data with which we’ll prepare our buffer. The following 
explanations apply to the table which follows: 

The data for GAP2 through GAP4 inclusive (one complete record) 
repeat for each sector. For example, a format with 29 sectors would 
have the corresponding block repeated 29 times in the buffer. You 
have to determining the values specified with $XX yourself, 
although this isn’t very complicated. If you are formatting track 54, 
for example, the value for the track number would be 54. 

The value for the side number is generally 0 for the front side and 1 
for the back. 

The sector numbers form a sequence, usually starting with 1. The 
order is variable and might be 3, 6, 9, 1, 4, 7, 2, 5, 8 for a format 
with 9 sectors. The only important thing is that the sequence is 
complete. If the sectors are designated with 1, 2, 3, 5, 6, 7, 8, 9, 

10, a later READ SECTOR or WRITE SECTOR command with the 
m-bit set terminates after the third sector with a RECORD NOT 
FOUND error because the FDC couldn't find a sector number 4. 

Atari format is listed in the first column. Our table differs from the 
one found in A Hitchhiker's Guide to the BIOS. The length of the 
track trailer (GAP5) is listed there as 1401 bytes instead of 644 
bytes. If you add the values given in the Hitchhiker's Guide, it 
would appear that the track length is about 7000 bytes, which is not 
the case in reality. A buffer is prepared that is somewhat larger than 
what the track can actually hold, but no more than about 6250 bytes 
fits in one track. 


120 




Abacus 


Atari ST Disk Drives Inside and Out 


Number of sectors/sector size 



9 / 

512 

18 

/ 

256 

29 

/ 

128 

5 / 

1024 

GAPl 

60 

•k 

$4E 

42 

* 

$4E 

40 

k 

$4e 

60 

★ 

$4E 

GAP 2 

12 

k 

$00 

11 

★ 

$00 

10 

k 

$00 

40 

★ 

$00 

SYNC 

3 

k 

$F5 

3 

k 

$F5 

3 

k 

$F5 

3 

k 

$F5 

ID-AM 

1 

$FE 

1 

k 

$FE 

1 

k 

$FE 

1 

k 

$FE 

TRACK NUMBER 

1 

★ 

$XX 

1 

k 

$XX 

1 

k 

$XX 

1 

k 

$XX 

SIDE NUMBER 

1 

★ 

$xx 

1 

k 

$xx 

1 

k 

$xx 

1 

k 

$xx 

SECTOR NYMBER 

1 

★ 

$xx 

1 

k 

$xx 

1 

k 

$xx 

1 

k 

$xx 

SECTOR LENGTH 

1 

★ 

$02 

1 

k 

$01 

1 

k 

$00 

1 

k 

$03 

ID-CRC 

1 

k 

$F7 

1 

k 

$F7 

1 

k 

$F7 

1 

k 

$F7 

GAP 3 

22 

k 

$4E 

22 

k 

$4E 

22 

k 

$4E 

22 

k 

$4E 


12 

k 

$00 

12 

k 

$00 

12 

k 

$00 

12 

k 

$00 

SYNC 

3 

k 

$F5 

3 

k 

$F5 

3 

k 

$F5 

3 

k 

$F5 

DAM 

1 

k 

$FB 

1 

k 

$FB 

1 

k 

$FB 

1 

k 

$FB 

DATA 

512 

k 

$E5 

512 

k 

$E5 

512 

k 

$E5 

512 

k 

$E5 

GAP 4 

40 

k 

$4E 

26 

k 

$4E 

25 

k 

$4E 

40 

k 

$4E 

GAP 5 

664 

k 

$ 4E 

34 

k 

$ 4E 

33 

k 

$4E 

420 

k 

$4E 


Flowcharts of the Type III commands 

We have also prepared flowcharts for the Type III commands. These 
flowcharts are illustrated starting on the next page. 


121 




Abacus 


Atari ST Disk Drives Inside and Out 



122 















Abacus 


Atari ST Disk Drives Inside and Out 



123 
















Abacus 


Atari ST Disk Drives Inside and Out 



124 












Abacus 


Atari ST Disk Drives Inside and Out 



/ has an \ 
index impulse 
\^occurred^/ 



complete 
byte In DSR 



125 






Abacus 


Atari ST Disk Drives Inside and Out 


The Type IV command 
FORCE INTERRUPT 

Command word: 76543210 


1 1 0 1 13 12 II 10 

This command is the only one that may be passed to the controller while it is 
executing another command. It is used to stop the execution of a READ 
SECTOR command or WRITE SECTOR command with the m-bit set. 

There are three types of interrupts. These are determined by the status bits 
(10-13) in the command word. 10 and II have no meaning and should be 
cleared. Bits 12 and 13 select the type of interrupt as follows: 

($D4) 12 =1, interrupt on every index pulse 

($D8) 13 = 1, end current command with interrupt 

($D0) 12-13 = 0, end current command without interrupt 

The interrupt on every index pulse ($D4) can be used to determine the speed 
of the drive. Another use is the synchronization of the READ ADDRESS 
command with the start of the track. It is not necessary to start with the 
index pulse for the READ TRACK and WRITE TRACK commands. 

A command currently being executed can be terminated by the interrupts 
$D8 and $D0. It should be noted that the INTRQ output is not reset by 
reading or writing the command register after a $D8 interrupt as it usually 
is. This line can be reset only by following a $D8 interrupt with $D0 
interrupt and then reading the status register. 

If a FORCE INTERRUPT is sent to the FDC, a delay time of 16|is must be 
inserted before the next command or the interrupt won't be executed. 


4.2.2.4 Status interpretation 

We said that the programming of the peripheral components responsible for 
data transfer is handled almost exclusively by the operating system. In most 
cases, these components offer more features than are necessary for normal 
system operation. This is the reason that the less-frequently-used 
capabilities cannot be accessed through the operating system. 


126 



Abacus 


Atari ST Disk Drives Inside and Out 


In certain cases, however, these "sleeping" talents of the peripheral chips 
can make a programming problem much easier or even solve it. Why don't 
many programmers have enough confidence to wake these "talents"? Just 
because there's no operating system call to do it? No, the most common 
reason is "fear of status." 


This says that a programmer knows how a chip can accomplish a given 
task, but he doesn't know how to interpret the status which the chip returns. 
Often he doesn't know what status is returned after error-free execution 
because certain bits in the status register are almost always set. An OK 
status can therefore vary. Not knowing how to interpret the status results 
can stop a programming project dead in its tracks. It's a waste of time to try 
out all of the possibilities and determine the status returned in each case 
experimentally. But this isn't the only way to do it either. We have taken 
care of this for you with the floppy disk controller. 

Here again we have a table of the meanings of the individual status bits, 
which were previously described in section 4.2.2.2: 


Bit 

7 

6 

5 

4 

3 

2 

1 

0 


FDC status register 


C omman d 

Motor On (MO) 

Write Protect (WPRT) 
Record Type or 
Spin Up 

Record not found 
CRC-Error 
Track 0 
lost data 
Index inpulse or 
Data Request 
Busy 


Bit=l means 
Drive motor 
Disk write protected 
DATA MARK cleared 
Turn number reached 
Sector not found 
Checksum error 
Head at track 0 
Data loss 
Index pulse status 
Ready to transfer 
Command active 


It is of interest that we can determine whether or not the disk in the drive is 
write-protected, or even whether there is a disk in the drive at all, after the 
read/write head is positioned. 

All the commands from Type I to Type III have the following in common: 
Bit 7 is set (the motor is not turned off immediately) and bit 0 is cleared (the 
FDC has completed the command) in the status word, which is read 
immediately after a command. In addition, bit 5 (spin up) is set after a Type 
I command. 


127 




Abacus 


Atari ST Disk Drives Inside and Out 


The status after a Type I command 

Let's start with the status after a Type I command. In the command words 
used, the stepping-rate bits for 3ms track to track time are set (rO=l, rl=0). 


RESTORE command 

normal 

write protected 

01 (with MO option, no verify) 

A6 

E4 

01 (note (1)) 

A6 

E6 

05 (with MO option, with verify) 

A4 

E4 

09 (no MO option, no verify) 

A4 

E4 

0D (no MO option, with verify) 

A4 

E4 

SEEK command 

normal 

write protected 

11 (with MO option, no verify) 

A0 

E0 

11 (note (3)) 

A2 

E2 

11 (note (2)) 

A4 

E4 

11 (note (1)) 

A6 

E6 

15 (with MO option, with verify) 

A0 

E0 

15 (note (2)) 

A4 

E4 

19 (no MO option, no verify) 

A0 

E0 

19 (note (2)) 

A4 

E4 

ID (no MO option, with verify) 

A0 

E0 

ID (note (2)) 

A4 

E4 

STEP, STEP IN, STEP OUT 

normal 

write protected 

xl (with MO option, no verify) 

A) 

E0 

xl (note (2)) 

A4 

E4 

x5 (with MO option, with verify) 

A0 

E0 

x5 (note (2)) 

A4 

E4 

x9 (no MO option, no verify) 

A0 

E0 

x9 (note (2)) 

A4 

E4 

xD (no MO option, with verify) 

A0 

E0 

xD (note (2)) 

A4 

E4 


(1) This value is valid if the read/write head is already over track 0 
before a RESTORE or SEEK command to track 0. In addition to 
the track-0 bit, the IP bit is also set. This is because six index 
pulses are counted if the motor-on option is enabled. This means 
that the FDC determines that the desired track is reached during 
an index impulse and ends the command. 


128 


Abacus 


Atari ST Disk Drives Inside and Out 


(2) This status is encountered after a SEEK, STEP IN, or STEP 
OUT command when the read/write head is moved over track 0. 

(3) If the read/write head is already over the desired track (except for 
track 0) for a SEEK command, the IP bit is set in the status 
word. The same relationship applies here as in (1). 

In general, an error status can only be received after a Type I command if 
the verify bit is set in the command word. In addition: 

(a) If no ED field was found, the RNF bit is set. 
and 

(b) If no correct ID field was found, the RNF and CRC bits is set. 

The status is $B2 or $BA, or $F2 or $FA for a write-protected disk. 

If the whole thing happens on track 0, the track 0 is also set, of course. The 
status word then has the value $B6 or $BE, or $F6 or $FE for a 
write-protected disk. 

It occurs that the IP bit is always set in case of error. This has nothing to do 
with the motor-on option, however, but results because the fruitless search 
for an ID field is ended on the sixth index pulse. 

The status after a Type II command 

The status interpretation is somewhat simpler for Type II commands. After 
a successful WRITE SECTOR command the status register always contains 
the value $80. After a READ SECTOR command, the status word can also 
be $A0 if a sector with an "erased" data mark was read. Otherwise the value 
will also be $80 here. 

If the command was not successful, the status after a WRITE SECTOR 
command is one of the following: 

(a) $C0 after an attempt to write to a write-protected disk 

(b) $90 if the ID belonging to the desired sector was not found 

(c) $88 if the checksum (CRC) of the ID field was not correct 

(d) $84 if no reaction was made to a DATA REQUEST by the FDC 


129 



Abacus 


Atari ST Disk Drives Inside and Out 


After an error occurred during a READ SECTOR command: 

(a) $90 if the ID field belonging to the desired sector or the data mark 
was not found 

(b) $98 if the checksum (CRC) of the ID field was wrong 

(c) $88 if the checksum (CRC) in the data field indicated an error 

(d) $84 if no reaction was made to a DATA REQUEST by the FDC 

The status after a Type III command 

The status after a Type IE command is even simpler to evaluate. The value 
$80 indicates successful execution. In case of an error during a WRITE 
TRACK command, one of the following holds: 

(a) $C0 for a write-protected disk 

(b) $84 if no reaction was made to an FDC DRQ 

There is no such thing as improper execution of the READ TRACK 
command. The FDC simply reads the RD input between two index pulses, 
and it doesn't even matter if there's a disk in the drive or not. 

The only imaginable error, LOST DATA (status $84), cannot be evaluated 
because of a software error in a subprogram in the FDC. The LOST DATA 
is also set depending on the format read in addition to actual loss of data. 

For the READ ADDRESS command, a status value of $80 also means that 
no errors occurred. Otherwise, one of the following can result: 

(a) $90 if no ID field was found 

(b) $88 if the FDC found a checksum error in the ID field 

(c) $84 if no reaction was made to a DRQ 


130 



Abacus 


Atari ST Disk Drives Inside and Out 


4.2.3 The floppy interface 


The floppy disk connector on the back of the ST is a rather unusual 14-pin 
socket. Complete control of the drive and the data transfer takes place over 
these fourteen lines. This control is fairly easy to describe because the drive 
doesn't possess any intelligence of its own. 

This has one big advantage. The interface to such drives is standardized and 
is called the Shugart interface, and is found on many drives. This is the 
reason that it is so easy to connect foreign drives to the Atari ST. 

The Shugart interface has a 34-pin connector which is usually equipped 
with a ribbon connector. Half of these 34 pins are tied together and 
grounded. On a ribbon cable every other wire is a ground, so all of the odd 
pins are grounded. This results in some shielding between the signal lines, 
which is important given the high clock rates of the signals. 

Fourteen of the remaining eighteen lines are connected to the Atari. Let's 
look at these signals on the Shugart connector: 

Pin 2: Head Load 

A low signal on this line sets the read/write head on the diskette. 
This feature is designed to protect the disk because the head rubs 
on the disk only when it is actually going to access it. 
Unfortunately, this signal is not available on the ST because the 
WD1772 controller does not have this connection available. This 
line is often connected to "Motor on" however. 

Pin 3: Ground 

All odd-numbered lines through 33 are tied to ground. This 
ground connection is used for operation as well as shielding. 

Pin 4: In Use 

This signal tells the drive that it is connected and is used. It is not 
available on the Atari. 

Pin 6: Drive Select 3 

A low level on this line means that drive three is being selected. 
Only the drive which is assigned as drive three by a wire jumper 
in the drive reacts to commands, and all others remain neutral. 
This signal is not used on the Atari because a maximum of two 
floppies can be connected (0 and 1, or A and B). 


131 




Abacus 


Atari ST Disk Drives Inside and Out 


Pin 8: Index 

The drive uses this line to send a low pulse upon each rotation of 
the disk. This signal tells the controller that the data which follow 
are at the very start of the current track. This can be used to 
synchronize the controller. 

Pin 10: DriveSelect 0 

This signal corresponds to the one on Pin 6, except that it 
concerns drive 0 (Drive A). 

Pin 12: Drive Select 1 

As above, except for drive 2 (Drive B). 

Pin 14: Drive Select 2 

As above, except for drive 2. Not connected on the ST because 
only two drives are possible. 

Pin 16: Motor on 

A high level on this connection starts the motors of all drives and 
a low stops them. 

Pin 18: Direction 

This signal indicates the direction of the next step of the 
read/write head. If this pin is zero, the direction is in, toward 
track 79, while a 1 means out, toward track 0. 

Pin 20: Step 

A low pulse causes the step motor in the drive to move the 
read/write head one step in the direction specified. 

Pin 22: Write Data 

This line carries the serial data which are to be written to the disk. 

Pin 24: Write Gate 

This signal selects the data direction. If it is low, the disk is 
written, while a high signal indicates read. If the disk is 
write-protected, no write access is allowed by the drive. 

Pin 26: Track 0 

If the read/write head is over track 0, this pin is low. 

Pin 28: Write Protect 

A low on this line means that the diskette is write-protected. 


132 




Abacus 


Atari ST Disk Drives Inside and Out 


Pin 30: Read Data 

The data read from the disk are sent to the computer via this line. 
Pin 32: Side Select 

This line selects the desired side of the disk. A low level selects 
side 1 and a high selects side 0. This line is unused for 
single-sided drives. 

Pin 34: Ready 

A low level on this line indicates that a disk is inserted in the 
drive and that it is rotating normally. The computer can use this 
line to determine if the disk has been changed. This line is not 
connected to the Atari ST. 

All of these signals are TTL-compatible, meaning that 0-0.4 volts indicates a 
LO (zero) and 2.5-5.25 volts means HI (one). To ensure these signals, 
most drives have a set of pull-up resistors built into them. 

If several drives are connected in parallel, it is advisable to remove the 
resistors from all drives except the last one or the outputs on the Atari may 
be overloaded. On some drives (such as the Epson) the resistors are in a 
single package so that they can be removed easily. For the original Atari 
drives, which are Epson drives, by the way, this is not necessary. 


4.3 Connecting the disk drives 


The floppy disk drives which Atari sells for the ST are very easy to connect: 
Plug the cable into the computer and drive and you're done. 

It becomes more complicated if you want to connect a different drive. The 
first problem which we encounter is the connector, which at the time of this 
writing (5/86) is difficult or impossible to find. Solder pins soldered to a 
suitable circuit board or held in position by some other means can be used 
as a substitute. 

Once you have devised a suitable connector, you have to wire it. A shielded 
cable is highly recommended if the length exceeds about one meter. The 
high transfer rates lead to electrical effects like inductance and capacitance, 
which can have unfavorable effects on data transfer. The best way to avoid 
this is to use a cable in which the lines are individually shielded. 


133 




Abacus 


Atari ST Disk Drives Inside and Out 


After the connection between the Atari and the drive has been made, the 
cable must be connected. Here is the wiring table: 


ari ST 

Line 

Shugart connector 

1 

Read Data 

30 

2 

Side 0 select 

32 

3 

Ground 

all odd lines 

4 

Index Pulse 

8 

5 

Drive 0 select 

10 

6 

Drive 1 select 

12 

7 

Ground 

see above 

8 

Motor on 

16 

9 

Direction in 

18 

10 

Step 

20 

11 

Write Data 

22 

12 

Write Gate 

24 

13 

Track 00 

26 

14 

Write Protect 

28 


When these lines are connected to the two drives, all connections are in 
parallel. The selection between drives A and B is made directly in the drive. 
The jumpers in the drives must be set properly for this selection. 
Information on how to set the jumpers is found in the documentation for a 
given drive. 


134 


Chapter Five 














Abacus 


Atari ST Disk Drives Inside and Out 


The SH204 hard disk 


A hard disk is a significantly faster—and significantly more expensive— 
method of data storage. But the SH204 hard disk that Atari sells for use 
with the ST is available for a very reasonable price. 

What are the advantages and disadvantages of a hard disk? The first 
disadvantage is obviously the hard disk’s high cost. In addition, you can't 
exchange media for copying files and programs, or for backups and archival 
storage—all of which are possible with floppy diskettes. 

But if we look at the advantages which a hard disk has to offer, the 
investment becomes more appealing. A hard disk's first advantage is the 
speed at which it transfers data between the ST and the hard disk itself, 
approximately 10 times faster than floppy diskette operations. 

Another advantage is the capacity of a hard disk. The currently available 
device has a capacity of twenty megabytes. This can hold, for example, all 
of the programs and files for an extensive compiler together with the source 
files for your C or Pascal programs. Since these compilers are usually 
disk-oriented (i.e., they constantly access information on the disk), both the 
speed and large capacity of the hard disk represent significant advantages 
for working with compilers. 

A popular use of hard disks is in electronic data processing, where large 
quantities of data must be managed. Having to change disks all of the time 
in such applications simply wouldn't work. Imagine a bank teller having to 
insert the correct disk into the bank computer for every withdrawal! 

An Atari ST with a twenty megabyte hard disk probably isn't sufficient for 
the data processing needs of a bank. But it would work for managing a 
small business in which inventory, accounting, and payroll were done on a 
computer. This is the principle application of a hard disk. 

We will now look at how such a data set is managed by the hard disk and 
also by the computer connected to it. 


137 


Abacus 


Atari ST Disk Drives Inside and Out 


5.1 Function and design 


The function of a hard disk is very similar to that of a floppy disk drive. In 
both cases, one or more disks (just one in the Atari hard disk) rotate at a 
constant speed and a read/write head moves over it. There are some 
important differences from a floppy drive, however. The rotation speed of 
the hard disk is significantly higher than that of a floppy diskette, which 
makes possible the high access and transfer speeds. 

In order to protect the read/write head, which flies over a disk that rotates 
about ten times faster than a floppy diskette, it does not contact the disk at 
all. The head floats oyer the disk on a cushion of air that is so thin that the 
head would collide with a dust particle on the disk surface. 


Human Hair Speck of dust Finger print Read/write head 



With the high tangential speed of the disk, if the head contacts such a dust 
particle, it can lead to severe damage to the disk and/or the read/write head. 
This is called a "head crash," and it can have very expensive consequences 
in terms of lost data and actual physical damage to the drive. 

To minimize the chances of a head crash, the disk and the head are sealed in 
an airtight enclosure. This is why the media in hard disks are usually not 
exchangeable like diskettes. There are exchangeable-media hard drives 
available on the market, but they are quite expensive. Also, no such drive is 
currently available for the ST, so we will not explore this any further. 

Another difference between a diskette drive and the hard disk on the Atari 
ST shows up in the controller. The floppy disk controller built into the Atari 
ST is, as the name indicates, only responsible for the floppy drives. The 
hard disk has its own controller, which is built into the drive housing. This 
makes it considerably harder to connect a foreign hard drive to the Atari. 
Let's take a closer look at this controller. 


138 
































Abacus 


Atari ST Disk Drives Inside and Out 


5.1.1 The hard disk controller 


The controller used in the Atari ST hard disk is a very powerful device. This 
controller can achieve data transfer rates up to eight megabits per second, 
which is about one megabyte/second. This would fill the memory of a 
1040ST in one second! Unfortunately, this number does not apply to actual 
data transfer. 

One factor that dramatically slows the data transfer is the mechanism in the 
hard disk. This refers to the rotation speed of the disk and the step motor 
which moves the read/write head to the proper track on the disk. All of these 
points reduce the actual maximum speed of the data exchange, although it is 
still very high. 

The controller has a very simple internal structure. Its command set is so 
versatile that it even supports error correction. The hardware of the 
controller consists mainly of a disk controller, an encoder/decoder, and a 
microcontroller. These components have the following tasks or functions: 

The disk controller converts the data from serial into parallel and back again. 
In addition, it converts the data itself into a different bit pattern, which is 
then actually written to the disk. This different format allows simple read 
errors to be recognized. 

The encoder/decoder converts the data sent by the disk controller into 
electrical signals which control the write head. It also converts the signals 
which arrive from the head when reading into bits, whereby it also serves as 
a data separator (cf. floppy disk controller). 

The microcontroller works like an actual disk controller. Its tasks are: 

• interpretation of the commands from the computer 

• selection of the drive being accessed (usually there is only one) 

• selection of the head in the drive (top or underside of the disk) 

• control of the stepper motor which moves the read/write head 

• status reporting 

Here is a simple block diagram of the Atari hard disk controller: 


139 



Abacus 


Atari ST Disk Drives Inside and Out 


Atari Hard Disk Controller Block Diagram 



The operations which can be performed with the hard disk over the DMA 
bus are divided into five different phases, which are defined as follows: 

Reset phase 

Occurs when either the RESET button on the ST is pressed, the 
computer is turned on, or the RESET command is executed by the 
68000 processor. The bus and the HDC are reset to their initial states. 

Bus-free phase 

Occurs when no device is accessing the bus. 

Destination-selection phase 

Starts with calling a device by reseting the SEL line. The desired 
device is addressed through a set data bit on the 8-bit parallel bus. 
The addressed device (here: HDC) answers with a BUSY signal, 
upon which the SEL line is set again. Then starts the 

Information-transfer phase 

During this phase the following data are transferred: 

• the command block, 6 bytes from the ST to the HDC 

• the data block(s), if the command requires it 

• the status byte from the HDC to the ST, which indicates whether 
the operation was successful or whether an error occurred. This 
byte is always zero, however, so status transmission is possible 
through the recognition of a timeout 

• the completion byte from the HDC to the ST, a zero byte which 
signals the end of the entire operation 


140 




Abacus 


Atari ST Disk Drives Inside and Out 


Bus-release phase 

This phase is initiated by setting the BUSY line and means that the 
bus is free for the next operation. The bus is then back in the bus-free 
phase. 


5.1.1.1 Command structure 

The transfer of commands to the hard disk controller is precisely defined. 
Each command is sent a 6-byte block, called the command descriptor block. 
When the controller receives such a command, it acknowledges receipt to 
the initiator, the ST, through an interrupt. If the block contains a command 
to find a specific track (verify, format track, read, write), this will be 
performed automatically. The specified logical data block is converted by 
the controller to physical quantities like disk side and track number. 

The following diagram shows the structure of a command block: 


Byte 0: |xxxxxxxx| 


Byte 1 : 


xxxxxxxx 


Byte 2: xxxxxxxx 


Operation code 
.Controller Number 

Block address HI 
_Drive number 

Block address MID 


Byte 3 : 


Byte 4 : 


Byte 5: 


xxxxxxxx 


Block address LO 


xxxxxxxx 


xxxxxxxx 


Block number 


Controller byte 


141 



Abacus 


Atari ST Disk Drives Inside and Out 


Controller number 

This is a 3-bit value (0-7) which represents the number of the selected 
controller. This allows up to eight different controllers to be 
connected and served. The number which addresses each individual 
controller is set with the help of three switches on the controller 
board. When a command arrives at the controllers over the common 
bus line, each one tests to see if it is the one being accessed. If not, it 
behaves as if it didn't exist. If so, communication between the 
computer (initiator) and the addressed controller (target) begins. If no 
controller answers the command within four seconds, the computer 
gives up: time out. 

Operation code: 

This code, also called the opcode, contains the command to be 
executed in five bits. This means that only commands from 0 to 31 
are possible. 

Drive number: 

Similar to the controller number, this is a 3-bit number which 
designates the selected drive. Each of the eight controllers can control 
up to eight drives, which means that 64 drives can be theoretically 
connected to the Atari. 

Block address: 

This 21-bit number designates the selected logical sector. The 
conversion of this number (up to 2097151) into the physical values is 
accomplished by the controller. The Atari hard disk contains 41616 
sectors, so the block addresses may not exceed this value and, since 
the block numbers start at zero, may not reach it either. 

Block counter: 

This counter determines the number of sectors to read or write. The 
counter must have a non-zero value (1-255). 

Control byte: 

This byte contains various specifications, depending on the given 
command. 


142 


Abacus 


Atari ST Disk Drives Inside and Out 


The following procedure must be executed in order to send such a command 
to the HDC: 

First, the processor is placed in the supervisor mode through the SUPER 
function ($20) of GEMDOS (TRAP #1), because some privileged accesses 
must be made to hardware registers. 

After this, the floppy-processing routines are disabled by setting the system 
variable FLOCK ($43E). This is necessary because both the FDC and the 
HDC are controlled via the same hardware registers. To make sure that there 
are no crossed signals, such as an OK from one controller when we are 
waiting for the OK from the other one, the FDC is essentially removed from 
the system so that it doesn't interfere. 

In the hardware register $FF8606, called WDL, bits 7 and 3 are set and all 
others cleared by writing the value $88. This selects the HDC and places the 
line Al, which is addressed through bit 1, to zero. 

Line Al is used to signal the HDC that a command byte (the first byte of a 
command block) will be transferred. 

Following this, the command byte is placed in register $FF8604, called 
WDC. The HDC accepts this byte and acknowledges reception with a 
0-signal on the HDC interrupt line. This line lies on bit 5 of the I/O port on 
the Multi-Function Peripheral chip (MFP), and can be found at address 
$FFFA01. 

This interrupt also occurs after each additional byte is transmitted. If it does 
not occur, the byte was either not recognized or the HDC is not ready to 
receive data. 

During the transmission of the command bytes, there is a maximum wait of 
100 milliseconds for the interrupt, and up to three seconds after the 
complete transmission of the command block, because the command must 
be completely executed before the HDC can respond OK. If no interrupt 
occurs within this time, the transmission of the command bytes is 
terminated and a timeout is indicated. 

If the command byte is transferred and acknowledged on time through the 
interrupt, an $8A is written in the WDL, which sets the Al line to 1 again. 

The remaining five bytes of the command block are now transferred 
according to the same scheme, except with bit 1 (Al) set. The byte is 


143 


Abacus 


Atari ST Disk Drives Inside and Out 


written to WDC together with an $8A in WDL, the computer waits 100 ms 
for an interrupt (else timeout) and the next byte is transferred. 

After transmission of the last byte (byte 5) of the command block, the 
computer waits a maximum of three seconds for the interrupt, so that the 
HDC has enough time to execute the command. 

Finally, the system variable FLOCK ($43E) is again set to 0 in order to 
permit floppy operations again, and last of all, the computer can be switched 
back into the user mode. 

Here is a small program which performs the steps listed above and sends a 
command block to the HDC. Please note that this works completely only if 
the command does not cause data transfer via DMA (such as READ and 
WRITE), because the DMA controller must then be programmed. We will 
come to this later. 

; ** Hard disk access S.D. ** 

; ** Send command-bytes from COM-field to HDC ** 


wdc 

= $ff8604 


wdl 

= $ff8606 


wdcwdl 

= wdc 


port 

= $fffaOl 


flock 

= $43e 


run: 


move.b 

#'0',num 


clr.l 

-(sp) 


move 

#$20,-(sp) 


trap 

#1 


addq. 1 

#6, sp 


move.1 

dO,spsave 


lea 

com,aO 


bsr 

send 


bra 

exit 

send: 


St 

flock 


move 

#$88,wdl 


clr.l 

dO 


moveq 

#5,d2 


/Timeout-report preparation 

/Switch to Supervisor-Mode 

/Alter stack pointer—save 

/pointer to command-block 
/Send command-block on HDC 
/Ready 

/* Send command-Block on HDC * 
/Floppy block 
/Select HDC, A1=0 

/Number: 6 Bytes 


144 


Abacus 


Atari ST Disk Drives Inside and Out 


loop: 

clr.l 

dO 



move.b 

(aO) +, dO 

/Greatest byte 


bsr 

send byte 

/Send byte to HDC 


bmi 

error 

/Timeout ! 


dbra 

d2,loop 

/ Loop 

cont: 

move 

#$8a,wdl 



bsr 

waitl 

/Wait a max. of 3 seconds 
/interrupt 


bmi 

error 

/Timeout ! 


move 

#$8a,wdl 



move 

wdc,dO 

/Get status-byte 


move 

#$80,wdl 

/Deselect HDC 


move 

wdc,dl 

/Get completion-byte 


clr 

flock 

/Stop floppy disk access 


rts 


/Ready 

exit: 

move.1 

spsave,-(sp) 



move 

#$20,-(sp) 



trap 

#1 

/Switch to User-Mode 


addq.1 

#6, sp 


t 

rts 


/End as subroutine 


clr. w 

- (sp) 



trap 

#1 

/Return to desktop 

error: 

clr 

flock 

/Show error 

/Stop floppy disk access 


move. 1 

#senderr,dO 



bsr 

pline 

/Display error message 


bra 

exit 

/and end 

send_byte 

: 


/* Semd a byte to the HDC 


swap 

dO 

/Byte in HIGH-value 


move 

#$8a,dO 

/$8A in LOW-value 


move. 1 

d0,wdcwdl 

/Set WDC and WDL 


bra 

wait 

/Wait for OK (Interrupt) 

waitl: 

add.b 

#1,num 

/Running number+1 


move. 1 

#450000,d3 

/Timeout for 3 seconds 


bra 

waitl 

/Wait... 

wait: 

add.b 

#1,num 

/Running number+1 


145 



Abacus 


Atari ST Disk Drives Inside and Out 



move.1 

#15000,d3 

/Timeout for 100 ms 

waitl: 





subq.l 

#1, d3 

/Timeout counter-1 


bmi 

timeout 

/Timeout ! 


move.b 

port,dO 

/Load I/O-Port 


and. b 

#$20,dO 

/Combine bit 5 


bne 

waitl 

/If it's still set. 




/continue waiting 


moveq 

#0, d3 

/Display OK 


rts 


/Ready 

timeout: 





moveq 

#-l,d3 

/Don't display OK 


rts 



pline: 



/* Print a line on the 


move.1 

dO, - (sp) 



move 

#9,-(sp) 



trap 

#1 



addq.1 

#6, sp 



rts 



spsave: 

dc.l 1 



senderr: 

dc.b "ERROR in 

i send byte " 


num: 

dc.b "1. time! 

", 10,13,0 


com: 

dc.b $b,$0,$0, 

0,0,$0 



align 

end 


The command block bytes which this program transmits cause the 
read/write head of the hard disk to move to track 0 ($B=Seek). The program 
contains an error output for testing purposes which displays a timeout on 
the screen. This section can be omitted, of course, since it only checks to 
see that the command block was properly transmitted. 

The transmission of a read or write command to the HDC is somewhat more 
complicated. In addition to transferring the command block, the DMA 
(Direct Memory Access) controller, which is responsible for the transfer of 
data between the hard disk and computer memory, must be programmed. 

The DMA controller requires the following information: 

• the memory address from which the data will be read or to which 
they will be written. This address is written in the hardware 
registers $FF8609, $FF860B, and $FF860D—first the low byte, 
then the middle byte, and last the high byte of the address. Since 


146 


Abacus 


Atari ST Disk Drives Inside and Out 


this represents a 24-bit address instead of a full 32 bits, the 
address can "only" be between 0 and $FFFFFF (also used for 
FDC programming). 

• the direction in which the data are to be transferred (read or 
written). The DMA controller gets this information from bit eight 
of the WDL word, whereby 0 means read and 1 means write 
outside of memory. 

• the status of the DMA controller, on or off. The DMAC gets this 
information from bit six of the WDL register $FF8606. Normally 
the DMA controller is always on, meaning bit 6 = 0. 

The exact moment at which the DMAC is given this information is also 
important so that any operations in progress are not disturbed. If we want to 
read from the hard disk, the command byte is first sent to the HDC and then 
the DMA address is set. This prevents the DMAC from loading undesirable 
information into memory because the HDC first waits for the additional 
bytes of the command block after receiving the command block. 

To write to the hard disk, the DMA address is set first, and then the 
command byte is transferred. You can see how this is done in the program 
HDC tools in section 5.1.1.3. First, however, we stick to theory and take 
a look at the HDC commands. 


5.1.1.2 List of commands 

The command set used for the ST hard disk contains only nine different 
commands. Other commands are listed in the various manuals for the hard 
disk, but either they don't work as indicated, or they don't work at all. Here 
is an overview of the working commands and their hexadecimal opcodes: 


Opcode 

Command 

00 

Test Unit Ready 

01 

Restore 

03 

Request Sense 

04 

Format Drive 

08 

Read 

0A 

Write 

0B 

Seek 

15 

Mode Select 

IB 

Seek to shipping position 


147 


Abacus 


Atari ST Disk Drives Inside and Out 


The following is an explanation of the individual commands, together with 
their parameter bytes. The character indicates that a byte has no 
meaning, and should be cleared. 

Test Unit Ready (00) 

With this command the computer can address the bus and determine which 
devices are connected. 


Byte 0 : 


Byte 1 : 


Byte 2 to 5: 


| xxxOOOOOI 



| XXX 


Command 00, Test Unit Ready 
Controller Number 


Drive number 


If the specified drive is turned on and ready, a zero will be returned in the 
status byte, else the Check Condition bit will be set 

Restore (01) 

This command resets the HDC to its initial state and causes the drive 
read/write head to move to track 0. 


Byte 0 : 


Byte 1 : 


Byte 2 to 5: 


| xxxOOOOl| 



| XXX-I 


Command 01, Restore 
Controller Number 


Drive number 


Request Sense (03) 

This command returns four bytes (read the WDC four times), of which only 
the first byte has any meaning. It contains the error code of the last 
command to be executed. If no error occurred, this will contain a zero. 


148 








Abacus 


Atari ST Disk Drives Inside and Out 


Byte 0 : 

Byte 1 : 

Byte 2 : 
Byte 3: 
Byte 4: 
Byte 5:: 


I xxxO 0 011| 



I xxx 


Command 03, Request Sense 
Controller Number 


Drive number 


| 00000100 | $04 bytes returned 


Format Drive (04) 

This command instructs the HDC to format the entire disk. It should go 
without saying that you shouldn't experiment with this command! 

Some parameters are included with the command: 

• the Data Pattern flag, which consists of two bits and determines 
what data will be written to the empty sectors. If the bits are not 
set (0), all sectors will be written with $6C. If the bits are set, the 
byte passed in command byte 2 will be written. 

• Data Pattern. Here is the byte with which the formatted sectors 
will be filled if the Data Pattern flag is set. If the flag is not set, 
this byte has no meaning. 

• Interleave factor. This value specifies the distance between two 
consecutively numbered sectors on the disk. If the factor is 1, the 
sectors will be written on the track in order. If, for example, it is 
2, another sectors is placed between sectors 1 and 2. The order of 
the seventeen sectors on the track would be as follows: 

Floating number 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

— 1 - 1 1 - 1 - 1 - 1 - 1 - 1 - 1 1 1 1 - 1 — I - 1 - 1 

110 2 11 3 12 4 13 5 14 6 15 7 16 8 17 9 

Sector number 


149 








Abacus 


Atari ST Disk Drives Inside and Out 


This means that two revolutions of the disk are necessary in order to read all 
of the sectors in a track. This makes reading a track longer, but also more 
reliable because there is a small pause after reading each sector. Normally 
this factor is set to 1. 


Byte 0 : 


Byte 1: 


Byte 2 : 


| xxxO010 0| 



Command 04, 
Controller 


Format 

Number 


Drive 


| xxx-xx-| 



| xxxxxxxx| 


Data pattern flag 
Drive number 
Data pattern 


Byte 3: 
Byte 4: 
Byte 5:: 


| xxxxxxxx | Interleave factor HI 
(should be 0) 

| xxxxxxxx | Interleave factor LO 
(normally 1) 


Read sector (08) 

This command instructs the controller to move the read/write head to the 
track which contains the desired start sector, to read the specified number of 
sectors, and to transmit them to the computer. In addition to the transfer of 
the command block to the HDC, the DMAC must be programmed so that 
the arriving data are written into the appropriate area of memory. 


Byte 0 : 

Byte 1 : 

Byte 2 : 

Byte 3 : 

Byte 4 : 

Byte 5:: 


| xxxOl000 | 



Command 08, Read Sectors 
Controller Number 


Sector number HI 
Drive number 


| xxxxxxxx | 
I xxxxxxxx | 
I xxxxxxxx I 

I-, 


Sector number MID 

Sector number LO 

Number of sectors to 
be read 


150 






Abacus 


Atari ST Disk Drives Inside and Out 


Write Sectors (OA) 

This command writes sectors on the disk. The head is moved to the 
corresponding track and the data sent via the DMA channel are received and 
written to the sectors. The DMAC must again be programmed in addition to 
sending the command block. 


Byte 0 : 


Byte 1: 


Byte 2: 
Byte 3: 
Byte 4: 
Byte 5: : 


I xxxOOlOl| 


Command OA, 
■Controller 


Write 

Number 


Sectors 


| xxxxxxxx| 



Sector number HI 
Drive number 


| xxxxxxxx| Sector number MID 


I xxxxxxxx| Sector number LO 

I xxxxxxxx | Number of sectors to 
be written 


Seek (OB) 

The read/write head in the drive is moved by this command. The controller 
calculates the corresponding track from the sector number passed with the 
command and moves the head there. 


151 




Abacus 


Atari ST Disk Drives Inside and Out 


Byte 0 : 


Byte 1: 


| xxxOlOll| 



Command OB, Seek 
Controller Number 


| xxxxxxxx| 



Sector 

Drive 


number 

number 


HI 


Byte 2: |xxxxxxxx | Sector number MID 

Byte 3: Ixxxxxxxx | Sector number LO 

Byte 4 : I-I 

Byte 5:: I-I 

Mode Select (15) 

This command is used for setting the parameters for formatting the hard 
disk. A 16-byte clock is sent to the HDC after passing the command (and 
programming the DMAC). 


Byte 0 : 

Byte 1: 

Byte 2 : 
Byte 3: 
Byte 4 : 
Byte 5:: 


| xxxlOlOl| 



Command $15, Mode 
Controller Number 


Select 


| xxx-I 

-*-*-Drive number 


| 00010110 | = 16 bytes will be given 


152 









Abacus 


Atari ST Disk Drives Inside and Out 


Seek to shipping position (IB) 

This command causes the read/write head to move to a position where it is 
safe against movements of the drive. This position is called the shipping 
position because it is provided for transporting the drive. 

The program SHIP . PRG moves the heads in all connected hard drives to 
this position. It should always be run before moving a hard disk. It should 
be noted that the screen should be free of all hard disk directory windows 
when calling this program, otherwise the hard disk directory will be read 
when the program is done, moving the head out of its safe position. 


Byte 0 : 


Byte 1: 


| xxxllOll| 



Command IB 

Seek to Shipping Position 
Controller Number 


| xxx 


.Drive number 


Byte 2 to 5 : | 


5.1.1.3 HDC tools 

To demonstrate read and write accesses to the hard disk, here is a program 
which reads one or more sectors and transfers them to memory, or writes 
data to sectors from memory. In the example, eight sectors from sector 132 
on are loaded into memory. This is where the directory of the first hard disk 
partition is stored. 

This program also contains a simple method of transmitting the command 
block, similar to the example in section 5.1.1.1. 

;** Read/write hard disk sector, send command ** 


wdc 

= $ff8604 

;FDC/HDC access 

wdl 

= wdc+2 ; 

DMA-Mode/Status 

dm a 

= $ff8609 

;DMA-address HI 

flock 

= $43e ;Floppy-VBL-Flag 

port 

= $fffaOl 

/Parallel port. 


DMA-sector count 


bit 5=HDC-IRQ 


153 






Abacus 


Atari ST Disk Drives Inside and Out 


run: 



clr.l - 

(sp) 



move 

#$20,-(sp) 



trap 

#1 

/Switch to Supervisor-Mode 


addq.1 

#6, sp 



move.1 

dO,spsave 

/Store user stack pointer 

bpl: 

bra 

put 

/for transfer only 


pea 

BUFFER 

/Buffer address 


move 

#8, -(sp) 

/8 sectors 


move.1 

#132,-(sp) 

/Up to sector 132 


bsr 

read 

/Read sector(s) in buffer 


bra 

bp2 


put: 

bsr 

send 

/Transfer command block 

bp 2: 

move.1 

spsave,-(sp) 



move 

#$20,-(sp) 



trap 

#1 

/Switch to User-Mode 


addq.1 

#6, sp 


/ 

rts 


/Return for subroutine 




/or 


clr 

- (sp) 



trap 

#1 

/Return to Desktop 

send: 

;* Transfer 

command block * 



lea 

wdc,aO 



lea 

com,al 

/Pointer to command block 


st 

flock 

/Save floppy 


move 

#$88,wdl 

/Select HDC, A1=0 


clr.l 

dO 



moveq 

#5, dl 


loop: 

clr. 1 

dO 



move .b 

(al)+,dO 



bsr 

send byte 

/Send byte on HDC 


bmi 

tout 

/Timeout! 


dbra 

dl,loop 

/Otherwise keep looping 


bsr 

waitl 

/Wait a max. of 3 seconds 


bmi 

tout 

/Timeout! 


move 

wdc,d6 



move 

#$80,wdl 

/Else 


clr 

flock 

/stop disk access 


rts 


/Ready 


154 




Abacus 


Atari ST Disk Drives Inside and Out 


read: 


write: 


* Sector (s) 

read * 

lea 

wdc,aO 

St 

flock 

move 

#$88,2(aO) 

nop 


move.1 

#$08008a, (aO) 

move.1 

10(sp),-(sp) 

bsr 

setdma 

addq.1 

#4, sp 

bsr 

set parameters 

bmi 

tout 

move 

#$190,2(aO) 

nop 


move 

#$90,2(aO) 

nop 


move 

8(sp),(aO) 

nop 


move 

#$8a,2(aO) 

nop 


move.1 

#0,(aO) 

bsr 

waitl 

bmi 

tout 

move 

#$8a,2(aO) 

bra 

exec 

* Sector(s) 

write * 

lea 

wdc,aO 

st 

flock 

move.1 

10(sp),-(sp) 

bsr 

setdma 

addq.1 

#4, sp 

move 

#$88,2(aO) 

nop 


move.1 

#$0a008a,(aO) 

bsr 

set_parameters 

bmi 

tout 

move 

#$90,2(aO) 

nop 


move 

#$190,2(aO) 

nop 


move 

8(sp),(aO) 


/Save Floppy-VBL routine 
/HDC-access, A1=0 

;READ command 

/Buffer address 
/Set DMA 

/Amount and number of sectors 
/Timeout ! 

/Switch to READ 

/Send sector count to DMA 

/Start transfer 

/Wait a max. of 3 seconds 

/Timeout ! 

/Save Floppy-VBL 
/Set DMA address 

/HDC access, A1=0 
/WRITE command 

/Amount and number of sectors 
/Timeout ! 

/Switch to WRITE 

/Send sector count to DMA 


155 




Abacus 


Atari ST Disk Drives Inside and Out 



nop 




move 

#$18a,2(aO) 



nop 

move.1 

#$100,(aO) 

;Begin transfer 


bsr 

waitl 

;Wait a max. of 3 seconds 


bmi 

tout 

/Timeout ! 


move 

#$18a,2(aO) 


exec: 

nop 

move. 1 

(aO),d6 

;Get HDC/DMA status in D6 


and. 1 

#$ffOOff,d6 

;HI=HDC, LO=DMA 

tout: 

move 

#$80,2(aO) 

/Switch to FDC 


nop 

move. 1 

(aO),d7 

/Get completion byte 


and. 1 

#$ffOOff,d7 

/HI=HDC (0), LO=DMA 


clr 

flock 

/Stop Floppy-VBL routine 


rts 


/Ready 

set parameters: ;Set sector number and 

sector count 


move 

#$8a,2(aO) 



bsr 

wait 

/Wait for HDC-OK 


bmi 

setpx 

/Timeout ! 


clr 

dO 



move.b 

4 +5(sp),dO 

/Sector no. HI 


bsr 

send_byte 



bmi 

setpx 



move.b 

4+6(sp),dO 

/Sector no. MID 


bsr 

send_byte 



bmi 

setpx 



move.b 

4+7(sp),dO 

/Sector no. LO 


bsr 

send_byte 



bmi 

setpx 



move 

4+8(sp),dO 

/Number of sectors 


bsr 

send_byte 


setpx: 

rts 


/Ready 

send byte: 

; * Send 1 

byte to HDC * 



swap 

dO 



move 

#$8a,dO 



move. 1 

dO,(aO) 




156 



Abacus 


Atari ST Disk Drives Inside and Out 



bra 

wait 


waitl: ; 

Wait a max. of 

3 seconds for OK 



move.1 

#450000,count 



bra 

waitl 


wait: ; 

Wait a max. of 

100 ms for OK 



move.1 

#15000,count 


waitl: 

subq.1 

#1,count 



bmi 

timeout 



move.b 

port,dO 



and.b 

#$20,dO 

;HDC-Interrupt ? 


bne 

waitl 

; no 


moveq 

rts 

#0, dO 

;Yes => OK 

timeout: 

move.1 

terrline,dO 



bsr 

pline 

/Send 'Timeout' 


moveq 

rts 

#-l,dO 

/Display Timeout 

setdma: 

; * Set DMA-address * 



move.b 

7(sp),dma+4 

/LO 


move.b 

6(sp),dma+2 

/MID 


move.b 

5(sp),dma 

/HI 


rts 



pline: 

. * p r int line 

on screen * 



move. 1 

dO,-(sp) 



move 

#9, -(sp) 



trap 

#1 



addq.1 

#6, sp 



rts 



errline: 

dc.b "Timeout encountered!". 

10,13,0 

com: 

dc.b $b, 0, 

0,132,0,0 


ALIGN.L 




count: 

dc.l 1 


/Timeout counter 

spsave: 

dc.l 0 


/User stack point 


BUFFER: ds.B 512*8,$FF ;BUFFER FOR 8 SECTORS 

end 

This program gives you the ability to load sectors directly from the hard 
disk or write information to them. The status information is written in 
register D6, which can be displayed using a machine-language monitor or 
debugger such as SID or the AssemPro debugger. 


157 




Abacus 


Atari ST Disk Drives Inside and Out 


The difference between this program and the functions available in the 
operating system for reading and writing sectors is that the operating system 
functions can access only the selected partition on the disk. If you want to 
read sector 0 from the hard disk, for example, you must do it with the 
program above. 


5.1.1.4 Partition analyzer 

Sector zero of the hard disk is very interesting because it contains 
information about the hard disk and its partitions. The following program 
can be used to read and evaluate this information. Among other things, it 
contains parts of the previous program (read), which can be taken directly 
from the previous source code. 

The program reads sector 0 of the hard disk and interprets the data it 
contains. These are then displayed on the screen in hexadecimal. 


;** Partition Analyzer S.D. HD 3** 


wdc 

= $ff8604 


/FDC/HDC-Access, DMA sector count 

wdl 

= wdc+2 


;DMA-Mode/Status 

dma 

= $ff8609 


;DMA-address HI 

flock 

= $43e 


;Floppy-VBL flag 

port 

= $fffaOl 


/Parallel port, bit 5=HDC-IRQ 

run: 





lea 

stp,sp 



clr.l 

- (sp) 



move 

#$20,-(sp) 



trap 

#1 

/Switch to Supervisor-Mode 


addq.1 

#6, sp 



move.1 

dO,spsave 

/Store user stack pointer 


pea 

buf 

/Buffer address 


move 

#1, -(sp) 

/1st sector 


move.1 

#0,-(sp) 

/from sector 0 


bsr 

read 

/Read sector(s) in buffer 


move.1 

spsave,-(sp) 



move 

#$20,-(sp) 



trap 

#1 

/Switch to Oser-Mode 


addq.1 

#6, sp 



158 





Abacus 


Atari ST Disk Drives Inside and Out 


move.1 

#head,dO 


bsr 

pline 

/Print amount 

move.1 

#hi cc,dO 


bsr 

pmsg 


move 

buf+$lb6,dO 


bsr 

pword 

/Print cylinder number 

bsr 

pcrlf 


move.1 

#hi_dhc,dO 


bsr 

pmsg 


move.b 

buf+$lb8,dO 


bsr 

pbyt 

/Display number of heads 

bsr 

pcrlf 


move.1 

#hi_lz,dO 


bsr 

pmsg 


move.b 

buf+$lbe,dO 


bsr 

pbyt 

/Display park position 

bsr 

pcrlf 


move.1 

#hi rt,dO 


bsr 

pmsg 


move.b 

buf+$lbf,dO 


bsr 

pbyt 

/Output seek rate 

bsr 

pcrlf 


move.X 

#hi_in,dO 


bsr 

pmsg 


move.b 

buf+$lcO,dO 


bsr 

pbyt 

/Output interleave factor 

bsr 

pcrlf 


move.1 

#hi_spt,dO 


bsr 

pmsg 


move.b 

buf+$lcl,dO 


bsr 

pbyt 

/Display sectors/track 

bsr 

pcrlf 


move.1 

#hd size,dO 


bsr 

pmsg 


move.1 

buf+$lc2,dO 


bsr 

plong 

/Display sectors 
/of hard disk 

bsr 

pcrlf 


move.1 

#bsl_count,dO 



159 




Abacus 


Atari ST Disk Drives Inside and Out 


loop: 


pon: 


noboot: 


bsr 

pmsg 


move. 1 

buf+$1fa,dO 


bsr 

plong 

;Display number of dead 



; sectors 

bsr 

pcrlf 


clr 

d5 


clr.l 

d6 


lea 

buf+$lc6,a6 

/Partition field 0 

bsr 

key 


bsr 

pcrlf 


move.b 

d5, px_on 


add.b 

#'0',px_on 


cmp.b 

#0,0 (a6,d6) 

/Partition active? 

bne 

pon 

;Yes 

move.1 

#' out',px_on+14 

;Else display 'Out' 

move.1 

#px_on,dO 


bsr 

pline 


bra 

nextp 


move.1 

#' on ',px_on+14 


move.1 

#px on,d0 


bsr 

pline 

/Display 'Partition on' 

and.b 

#$80,0(a6,d6) 

;Bootable? 

beq 

noboot 

;No 

move. 1 

#boot,dO 


bsr 

pline 

/Else display 'Bootable 

move. b 

1(a6,d6),px_id+18 

move . w 

2 (a6,d6),px_id+19 

move. 1 

#px_id,dO 


bsr 

pline 


move.1 

#px start,dO 


bsr 

pmsg 


move .1 

4 (a6,d6),dO 


bsr 

plong 

/Display start sector 

bsr 

pcrlf 


move. 1 

#px_size,dO 


bsr 

pmsg 


move.1 

8(a6,d6),dO 


bsr 

plong 

(•Display sectors/track 

bsr 

pcrlf 



160 




Abacus 


Atari ST Disk Drives Inside and Out 


nextp: 


read: 


tout: 


addq 

#1, d5 


add 

#12,d6 


cmp 

#4*12,d6 


bit 

loop 


bsr 

key 

;wait for keypress 

clr 

- (sp) 


trap 

#1 

/Return to Desktop 

l sector(s) 

(as above) 


lea 

wdc,aO 


St 

flock 

/Save floppy-VBL routine 

move 

#$88,2(aO) 

/HDC access, A1=0 

nop 

move.1 

#$8008a, (aO) 

/READ command 

move. 1 

10(sp),-(sp) 

/Buffer address 

bsr 

setdma 

/Set DMA 

addq. 1 

#4, sp 


bsr 

set parameters 

/Set amount and 

bmi 

tout 

/number of sectors 

/Timeout encountered! 

move 

#$190,2(aO) 


nop 

move 

#$90,2(aO) 

/Switch to READ 

nop 

move 

8(sp),(aO) 

/Send sector count to DMA 

nop 

move 

#$8a,2(aO) 


nop 

move.1 

#0,(aO) 

/Start transfer 

bsr 

waitl 


bmi 

tout 


move 

#$8a,2(aO) 


move.1 

(aO),d6 

/Get HDC/DMA status 

and. 1 

#$ffOOff,d6 

/HI=HDC, LO=DMA 

move 

#$80,2(aO) 

/Switch to FDC 

nop 

move.1 

(aO),d7 

/Get completion byte 

and. 1 

#$ff00ff,d7 

/HI=FDC, LO=DMA 

clr 

flock 

/Release floppy-VBL-routine 

rts 


/Ready 


161 




Abacus 


Atari ST Disk Drives Inside and Out 


set parameters: ;Set 

sector numbers and sector count 


move 

#$8a,2(aO) 


bsr 

wait /Wait for HDC-OK 


bmi 

setpx /Timeout ! 


clr 

dO 


move.b 

4+5(sp),d0 /Sector no. HI 


bsr 

send_byte 


bmi 

setpx 


move.b 

4+6(sp),d0 /Sector no. MID 


bsr 

send_byte 


bmi 

setpx 


move.b 

4+7(sp),d0 /Sector no. LO 


bsr 

send_byte 


bmi 

setpx 


move 

4+8(sp),d0 /Number of sectors 


bsr 

send_byte 

setpx: 


rts 


send byte 

: /Send 1 

byte to HDC 


swap 

dO 


move 

#$8a,d0 


move.1 

dO,(aO) 


bra 

wait 

waitl: 

/Wait a max. 

of 3 seconds for OK 


move. 1 

#450000,count 


bra 

waitl 

wait: 

/Wait a max. 

of 100 ms for OK 


move. 1 

#15000,count 

waitl: 


subq.l 

#1,count 


bmi 

timeout 


move.b 

port,dO 


and .b 

#$20,dO /HDC-Interrupt ? 


bne 

waitl /No 


moveq 

rts 

#0,dO /Yes => OK 

timeout: 


move. 1 

#errline,dO 


bsr 

pline 


moveq 

rts 

#-l,d0 /Display timeout 

setdma: 

/Set DMA-addresse 


move.b 

7(sp),dma+4 /LO 


162 




Abacus 


pline: 
pcrlf: 

pchar: 

pmsg: 


plong: 

pword: 

pbyt: 

phexwll: 


phexnib: 


Atari ST Disk Drives Inside and Out 


move.b 

6(sp),dma+2 

move.b 

5(sp), dma 

rts 



/Print Line/CR 


bsr 


pmsg 

/Print CR,LF 



move 


#10,dO 

bsr 


pchar 

move 


#13,dO 

/Print Character 

DO 

move 


dO,-(sp) 

move 


#2, -(sp) 

trap 


#1 

addq. 1 


#4, sp 

rts 



/Print Line 

(DO) 


move.1 


dO, -(sp) 

move 


#9, -(sp) 

trap 


#1 

addq 


#6, sp 

rts 



/Display DO 

as an 8-digit hex 

moveq 


#7,dl 

bra 


phexwll 

/Print hex-word 

DO 

swap 


dO 

moveq 


#3, dl 

bra 


phexwll 

/ Print hex- 

■byte 

DO 

moveq 


#1, dl 

ror. 1 


=#= 

00 

a 

o 

rol.l 


#4, dO 

move.1 


dO, -(sp) 

move.1 


dl, -(sp) 

bsr 


phexnib 

move.1 


(sp)+,dl 

move.1 


(sp)+,dO 

dbra 


dl,phexwll 

rts 



and. 1 


#$0f,d0 

add.b 


#$30,dO 


;MID 

;HI 

; ** other subroutines ** 


number 


163 



Abacus 


Atari ST Disk Drives Inside and Out 


cmp. b 

#$3a,d0 

bcs 

phexnl 

add. b 

#7, dO 

bra 

pchar 


;Print character 


key: 


bsr pcrlf 

move.1 #keyrasg,dO 

bsr pmsg 

move #1,-(sp) 

trap #1 /Wait for keypress 

addq #2,sp 

rts 


head: 

dc. b 

"** Hard disk-Analysis 

8/86 S.D. **",0 

hi cc: 

dc. b 

"Cylinder 

",o 


hi dhc: 

dc.b 

"Head 

", 0 


hi_lz: 

dc. b 

"Park Position 

",0 


hi_rt: 

dc.b 

"Seek Rate 

",0 


hi in: 

dc.b 

" Interleave 

",0 


hi spt: 

dc.b 

"Sectors/Track 

",0 


hd size: 

dc.b 

"Complete sectors 

",0 


bsl count: 

dc. b 

"Dead sectors 

",0 


align 





px on : 

dc. b 

"1st partition: 

",0 


boot: 

dc.b 

"Bootable 

",0 


px id: 

dc. b 

"Partition ID 

",0 


px start: 

dc. b 

"Start sector 

",0 


px size: 

dc. b 

"No. of sectors 

",0 


errline: 

dc. b 

"Timeout encountered!". 

10,13,0 

keymsg: 

dc. b 

"Press any key to 

continue",10,13,0 

align 

bss 




; DATA 

count: 

dc. 1 

1 


/Timeout counter 

spsave: 

dc.l 

0 


/User stackpointer 


ds. 1 

200 



STP: 

ds. 1 

1 



BUF: 

ds. b 

512 


/BUFFER FOR A SECTOR 


end 


And here is the BASIC loader, which creates the program anapart . TOS 
on the disk: 


164 





Abacus 


Atari ST Disk Drives Inside and Out 


10 

15 

20 

25 

30 

35 

40 

45 

50 

55 

60 

65 

70 

75 

80 

85 

90 

95 

100 

101 

102 

103 

104 

105 

106 

107 

108 

109 

110 
111 
112 

113 

114 

115 

116 

117 

118 

119 

120 
121 
122 

123 

124 

125 

126 

127 

128 




Analyze partition loader 




?:fullw 2:clearw 2:gotoxy 0,0 

? "File >> anapart.tos << now being created":?:?:? 

dim c%( 634):cs#=0 

for i=0 to 634 

read a$:c%(i)=val("&H"+a$) 

check#=check#+(c%(i)) 

next i 

if check#= 6754423.04 then 70 

?"Can't go any farther;something wrong with the DATA." 
goto 80 

bsave"anapart.tos",varptr(c%(0)), 1270 
? "The program >> anapart.tos « is now written." 
?:?"Please press a key";:a=inp(2):end 

I 

i ********* DATA for anapart.tos ********** 

I 

DATA 601A, 0000,04AE,0000,0000, 0000, 052C, 0000 
DATA 0000,0000,0000,0000,0000,0000,4FF9,0000 
DATA 07D6,4 2A7,3F3C, 002 0,4E41,5C8F, 23C0,0000 
DATA 04B2, 4879, 0000, 07DA,3F3C, 0001,2F3C, 0000 
DATA 0000,6100,01AO,2F39,0000,04B2,3F3C,0020 
DATA 4E41,5C8F,2 03C, 0000,0364,6100, 02AA, 203C 
DATA 0000, 0387,6100, 02BC,3039,0000, 0990, 6100 
DATA 02C4,6100,02 96,203C,0000,039A, 6100, 02A4 
DATA 1039,0000,0992,6100,02B4,6100,027E,203C 
DATA 0000, 03AD, 6100, 028C,1039, 0000, 0998, 6100 
DATA 029C,6100,0266,203C,0000,03C0,6100,0274 
DATA 1039,0000,0999,6100,0284,6100,024E,203C 
DATA 0000,03D3,6100,025C,1039,0000,099A,6100 
DATA 026C,6100,0236,203C,0000,03E6,6100,0244 
DATA 1039, 0000,099B, 6100,0254,6100, 021E, 203C 
DATA 0000,03F9,6100,022C,2039,0000,099C,6100 
DATA 022E, 6100, 0206, 203C,0000, 040C, 6100, 0214 
DATA 2039,0000,09D4,6100,0216,6100,01EE,4245 
DATA 4286,4DF9,0000,09A0,6100,0242,6100,01DC 
DATA 13C5,0000,0420,0639,0030,0000,0420,0C36 
DATA 0000, 6000, 6600, 001A,23FC, 206F, 7574,0000 
DATA 042E,203C,0000,0420,6100,01AC,6000,0070 
DATA 23FC, 2 0 6F,6E20, 0000,042E,203C, 0000, 0420 
DATA 6100,0194,023 6, 0 0 80,6000, 67 00, 000C, 203C 
DATA 0000, 04 33, 6100, 0180,13F6, 6001, 0000, 044F 
DATA 33F6,6002,0000,0450,203C,0000,043D,6100 
DATA 0166,203C,0000,0454,6100,0178, 2036, 6004 
DATA 6100,017C,6100,0154,203C,0000,0467,6100 
DATA 0162,2036,6008,6100,0166,6100,013E,5245 


165 





Abacus 


Atari ST Disk Drives Inside and Out 


129 

DATA 

130 

DATA 

131 

DATA 

132 

DATA 

133 

DATA 

134 

DATA 

135 

DATA 

136 

DATA 

137 

DATA 

138 

DATA 

139 

DATA 

140 

DATA 

141 

DATA 

142 

DATA 

143 

DATA 

144 

DATA 

145 

DATA 

146 

DATA 

147 

DATA 

148 

DATA 

149 

DATA 

150 

DATA 

151 

DATA 

152 

DATA 

153 

DATA 

154 

DATA 

155 

DATA 

156 

DATA 

157 

DATA 

158 

DATA 

159 

DATA 

160 

DATA 

161 

DATA 

162 

DATA 

163 

DATA 

164 

DATA 

165 

DATA 

166 

DATA 

167 

DATA 

168 

DATA 

169 

DATA 

170 

DATA 

171 

DATA 

172 

DATA 

173 

DATA 

174 

DATA 

175 

DATA 


DC7C,000C,BC7C,0030,6D00,FF52,6100,018E 
4267,4E41,41F9,OOFF,8604,50F9,0000,043E 
317C,0088,0002,4E71,20BC,0008,008A,2F2F 
000A,6100,00E8,588F,6100,0058,6B00,003C 
317C,0190,0002,4E71.317C,0090,0002,4E71 
3OAF,0008,4E71,317C,008A,0002,4E71,20BC 
0000,0000,6100,0076,6B00,0010,317C,008A 
0002,2C10,CCBC,OOFF,OOFF,317C,0080,0002 
4E71,2E10,CEBC,OOFF,OOFF,4279,0000,043E 
4E75,317C,008A,0002,6100,0050,6B00,0030 
4240,102F,0009,6100,0028,6B00,0022,102F 
OOOA,6100,001c,6BOO,0016,102F,OOOB,6100 
0010,6B00,OOOA,302F,OOOC,6100,0004,4E75 
4840,303C,008A,2080,6000,0010,23FC,0006 
DDDO,0000,04AE,6000,OOOC,23FC,0000,3A98 
0000,04AE,53B9,0000,04AE,6B00,0012,1039 
OOFF,FA01,C03C,0020,66EA,7000,4E75,203C 
0000,047A,6100,0020,7OFF,4E75,13EF,0007 
OOFF,860D,13EF,0006,OOFF,860B,13EF,0005 
OOFF,8609,4E75,6100,001A,303C,OOOA,6100 
0006,303C,OOOD,3FOO,3F3C,0002,4E41,588F 
4E75,2FOO,3F3C,0009,4E41,5C4F,4E75,7207 
6000,OOOE,4840,7203,6000,0006,7201,E098 
E998,2FOO,2F01,6100,0000,22IF,201F,51C9 
FFFO,4E75,COBC,0000,OOOF,D03C,0030,B03C 
003A,6500,0006,D03C,0007,60AA,619C,203C 
0000,0491,61AC,3F3C,0001,4E41,544F,4E75 
2A2A,2048,6172,6420,6469,736B,2D41,6E61 
6C79,7369,7320,382F,3836,2053,2E44,2E20 
2A2A,0043,796C,696E,6465,7220,2020,2020 
2020,203A,2000,4865,6164,2020,2020,2020 
2020,2020,2020,3A20,0050,6172,6B20,506F 
7369,7469,6F6E,2020,203A,2000,5365,656B 
2052,6174,6520,2020,2020,2020,3A20,0049 
6E7 4,6572,6C65, 617 6,652 0,2020,2020,203A 
2000,5365,6374,6F72,732F,5472,6163,6B20 
2020,3A20,0043,6F6D,706C,6574,6520,7365 
6374,6F72, 733A, 2000, 4465, 6164,207 3, 6563 
746F,7273,2020,2020,3A20,0000,3173,7420 
7061,7274,6974,696F,6E3A,2020,2020,0042 
6F6F,7461,626C,6520,0050,6172,7469,7469 
6F6E,2049,4420,2020,203A,2020,2020,2000 
5374,6172,7420,7365,6374,6F72,2020,2020 
3A20,004E,6F2E,206F,6620,7365,6374,6F72 
7320,203A,2000,5469,6D65,6F75,7420,656E 
636F,756E,7465,7265,6421,OAOD,0050,7265 
7373,2061,6E79,206B,6579,2074,6F20,636F 


166 


Abacus 


Atari ST Disk Drives Inside and Out 


176 DATA 6E74,696E,7565,OAOD,0000,0000,0002,1006 

177 DATA 140E,OAOA,OEOA,OEOA,OEOA,OEOA,OEOA,OEOA 

178 DATA OEOA,120E,0814,0612,0614,0C08,060A,16F8 

179 DATA 0E06,1A90,0000 

As we mentioned in the section on boot sectors, the px_f lag for each 
partition (maximum of four) indicates whether it is active and bootable. The 
Atari ST hard disk usually contains no bootable sectors because the ST 
cannot boot from the hard disk without the hard disk driver AHDI. PRG. 

The Seek Rate is usually given as 2, which corresponds to 3 ms per step. 
Interleave can be from 1 to 16 (sectors/track - 1), but it is usually 1. 
This represents the distance between two consecutively-numbered sectors 
on the track. 

The value behind Dead sectors indicates the number of defective sectors 
on the entire hard disk. These sectors are recognized and marked by the 
HDX. PRG program. A zero here means that the hard disk is perfect. 
Otherwise, one defective sector per megabyte is quite normal. 


5.2 Connecting the hard disk 


The 19-pin jack on the back of the ST is the DMA interface. The hard disk 
is connected to this jack by the included (short) cable and thereby has direct 
access to the memory in ST via the DMA controller. The reason for the 
short cable lies in the high data transfer rate. Wires tend to act as antennae, 
so that signals from one wire can find their way into another and disturb the 
data exchange if the wires are too long. 

The data are transferred in parallel over eight data lines (pins 1-8), so that an 
entire byte can be transferred at one time. In addition, this interface has 
various service lines like Reset (pin 12), which the ST can use to reset the 
hard disk, or an interrupt line (pin 10), which the hard disk uses to signal 
the ST and acknowledge the reception of data. 

You can theoretically connect up to eight controllers with up to eight hard 
drives each to the Atari ST, but since there is no second connector on the 
hard disk, this would require some homebrew modifications. 


167 




Abacus 


Atari ST Disk Drives Inside and Out 


To communicate with the hard disk, the computer must send its commands 
in the form of command blocks over the data lines. These command blocks 
have already been described. In the HDC program this was accomplished 
by simply selecting the appropriate register and writing the command byte. 
The byte is then on the data lines and can be accepted by the hard disk, 
which then acknowledges it over the interrupt line. 

In order to permit any data exchange at all, the drive program AHDI. PRG 
(Atari Hard Disk Interface) must be loaded. This and the HDX program run 
only if TOS is built into the computer; the driver works, but the HDX 
program does not, which makes it impossible to use the hard disk. The hard 
disk must be formatted before it can be used and also partitioned, because 
the controller can process a maximum of 16 megabytes per partition. 


5.3 Print the complete directory 


Folders are used heavily to organize the large number of files which the 
hard disk can store, and folders can even be nested within each other. This 
makes things much neater, but it can also make it harder to find a given file 
on the disk. 

To find the file, you must keep opening and closing folders in order to view 
their contents. It would be much more practical if we could just print out the 
entire contents of the hard disk or diskette. This is not directly possible with 
the Atari operating system, however. 

We will now present a program that does this. After it is loaded it asks for 
the drive designation (a-f) and then outputs the names of all the files on the 
selected disk to the printer, together with their folders. Folder contents are 
always indented two spaces to the right so that the nesting can be seen. 

In addition to the names, the length of each file is also given in decimal next 
to the name. An output like this can be quite long if the hard disk contains a 
lot of data, but it can be very useful for finding files and for checking to see 
if more than one copy of a file exists on the disk. 

Here is the program, written entirely in assembly language for the 
AssemPro assembler. If you use a different assembler, you may have to 
use an asterisk (*) instead of the semicolon for comments and replace the 
ds . x instruction with blk . x. 


168 


Abacus 


Atari ST Disk Drives Inside and Out 


;** Display complete disk directory 8/86 S.D. ** 


run: 


sfirst: 


sea: 


seax: 


lea 

stp,sp 

move. 1 

#menu,dO 

bsr 

pmsg 

bsr 

getkey 

cmp 

# ' a ' , dO 

bit 

run 

cmp 

#'f',d0 

bgt 

run 

move.b 

dO,fname 

bsr 

pcrlf 

lea 

fname+7,a6 

pea 

dta 

move 

#$la,-(sp) 

trap 

#1 

addq.1 

#6, sp 

clr 

d4 

lea 

DEPTH,a4 

move .b 

#0,(a4) 

bsr 

sfirst 

bra 

test 


move 

#$10,-(sp) 

pea 

fname 

move 

#$4e,-(sp) 

trap 

#1 

addq.1 

#8, sp 

cmp.b 

#'.',dta+30 

bne 

seax 

bsr 

snextl 

tst 

dO 

bne 

seax 

bra 

sea 

rts 



/Input drive 
/False drive 
/False drive 

/Pointer to end of filename+1 

/SETDTA 

/Depth=0 

/Pointer to counter()-array 
/Counter=0 

/subdirectory 

/SFIRST 

/Subdirectory? 


snext: 

add.b #1,(a4,d4) 

snextl: 

move #$4f,-(sp) 

trap #1 /SNEXT 


169 


Abacus 


Atari ST Disk Drives Inside and Out 



addq.1 

#2, sp 



rts 



next: 





bsr 

snext 


test: 





tst 

dO 



bne 

up 

;Go one level higher 


cmp.b 

#$10,dta+21 

/Subdirectory ? 


bne 

output 

/No: Display entry 


bra 

down 


up: 





subq 

#1, d4 

;Depth=-l 


bmi 

ready 

/Ready! 


sub 

#6,a6 


ml op: 





cmp.b 

#'\',-(a6) 



bne 

mlop 



bsr 

addwc 

/"*.* n ,0 added 


bsr 

sfirst 



clr 

d7 



move.b 

(a4,d4),d7 

/Counter(depth) in D7 


addq 

#1, d7 

/Counter+1 


move.b 

#0, (a4,d4) 


selop: 





subq 

#1, d7 



beq 

next 

/Ready for this level 


bsr 

snext 

/Look for counter(depth) entry 


bra 

selop 


down: 





move.1 

#subl,a5 



bsr 

prtline 



move.1 

#dta+30,a5 



bsr 

prtline 



bsr 

prtcr 

/Print CR 


addq 

#1, d4 

/Depth+1 


move.b 

#0,(a4,d4) 



subq.1 

#4,a6 



move 

#13,d7 



lea 

dta+30,a3 


flop: 





move.b 

(a3) +, dO 



beq 

f lopx 



move.b 

dO,(a6)+ 

/Transfer filename as path 



170 



Abacus 


Atari ST Disk Drives Inside and Out 



dbra 

d7,flop 


f lopx: 

bsr 

addwc 

;0 added 

bp: 

bsr 

sfirst 



bra 

test 

/Look for next depth 

addwc: 

move.b 

(a6)+ 



move.b 

(a6)+ 



move.b 

,(a6)+ 



move.b 

<a6)+ 



move.b 

#0,(a6)+ 



rts 



output: 

/Output entry 




cmp.b 

#8,$elb 

/Alternate-key pressed? 


bne 

outl 

/No 


bra 

ready 

/Else stop 

outl: 

lea 

dta+30,aO 



lea 

OUTLN,a5 

/Line output 


move 

d4, d5 


blop: 

move 

#' (a5)+ 

/Two spaces will assemble 

t 

dbra 

d5,blop 

move.w $#2020,(a5)+ 

blopl: 

move.b 

(aO)+ ,dO 



beq 

bloplx 



move.b 

dO,(a5)+ 



bra 

blopl 


bloplx: 

move.b 

#’ ',(a5)+ 

/ single space only 


cmp. 1 

#outln+26,a5 



bit 

bloplx 



move.1 

dta+26,dO 



bsr 

pdec8 



move.b 

#0,(a5) 



move. 1 

#outln,a5 



bsr 

prtline 



bsr 

prtcr 



bra 

next 


ready: 

/All done 




clr 

- (sp) 



trap 

#1 

/Exit => Desktop 


171 


Abacus 


Atari ST Disk Drives Inside and Out 


menu: 

subl: 
fname: 
ALIGN. W 


dc.b "** Directory Output S.D. **",10,13 

dc.b "Please input drive letter(a-f)0 
dc.b "Sub-Directory : ",0 
dc.b "a:\*. *", 0, " 


; ** Subroutines ** 


getkey: ;Get Key -> DO 


move 

#1,-(sp) 

trap 

#1 

and.l 

#$ff,dO 

addq. 1 

#2, sp 

rts 



pline: 
PCRLF: 


pchar: 


;Print Line/CR 

bsr pmsg 

/PRINT CR,LF 

move #10,dO 

bsr pchar 

move #13,dO 

/Print Character DO 

move d0,-(sp) 

move #2,-(sp) 

trap #1 

addq.l #4,sp 

rts 


prtline: 


prtx: 


/Print line from (a5) 


move.b 

(a5)+,dO 

beq 

prtx 

bsr 

prtchr 

bra 

prtline 

rts 



prtcr: 


prtchr: 


move 

bsr 

move 

move 
move 
trap 
addq. 1 
rts 


#10,dO 
prtchr 
#13,dO 

dO, -(sp) 
#5, -(sp) 
#1 

#4, sp 


/Print character 


/Print CR/LF 


/#2 for screen output 
/Print character 


172 


Abacus 


Atari ST Disk Drives Inside and Out 


pmsg: 



move. 1 

dO, -(sp) 


move 

#9, -(sp) 


trap 

#1 


addq 

rts 

#6, sp 

pdec8: 

number 


divu 

#10000,dO 


swap 

dO 


move 

dO, -(sp) 


swap 

dO 


and. 1 

#$ffff,d0 


move.1 

#1000,dl 


bsr 

decl 


move 

(sp) +, dO 

pdec4: 


move.1 

#1000,dl 

decl: 


divu 

dl, dO 


move.1 

dO, -(sp) 


add 

#'0 1 ,dO 


move.b 

dO,(a5)+ 


move.1 

(sp)+,dO 


swap 

dO 


and. 1 

#$ffff,d0 


divu 

#10,dl 


bne 

rts 

decl 

bss 

dta: 

ds . b 

44 

temp: 

ds. 1 

0 

depth: 

ds . b 

10 

ouTln: 

ds .b 

80 


ds. 1 

200 

stp: 

ds.l 

1 

end 


;Print Line (DO) 


/Display DO as 8-digit decimal 


(•Remainder 


/Display DO as 4-digit decimal 


(•Characters in output line 


; dat a 


Here is a BASIC loader that creates the program ALLDIR. TOS on the disk: 

10 i********* ALLDIR loader A.S. ********* 

15 1 

20 ?:fullw 2:clearw 2:gotoxy 0,0 


173 


Abacus 


Atari ST Disk Drives Inside and Out 


25 ? File >> alldir.tos << now being created":?:?:? 

30 dim c%( 364):cs#=0 

35 for i=0 to 364 

40 read a$:c%(i)=val("SH"+a$) 

45 check#=check#+(c%(i)) 

50 next i 

55 if check#= 3584742.08 then 70 

60 ?"Can't go any farther;something wrong with the DATA." 
65 goto 80 

70 bsave"alldir.tos",varptr(c%(0)), 730 

75 ? "The program >> alldir.tos << is now written." 

80 ?:?"Please press a key";:a=inp(2):end 
85 • 

90 ********** DATA for alldir.tos ********** 

100 DATA 601A,0000,02A8,0000,0000,0000,03AA,0000 

101 DATA 0000,0000,0000,0000,0000,0000,4FF9,0000 

102 DATA 064E,203C,0000,018C,6100,0250,6100,01FA 

103 DATA B07C, 0061, 6DE6,B07C, 0066, 6EE0, 13C0, 0000 

104 DATA 01E4,6100,01F8,4DF9, 0000, 01EB, 4879, 0000 

105 DATA 02A8,3F3C,001A,4E41,5C8F, 4244,4 9F9, 0000 

106 DATA 02D4,18BC, 0000, 6100, 0006, 6000, 0040,3F3C 

107 DATA 0010, 4879, 0000, 01E4,3F3C, 004E,4E41,508F 

108 DATA 0C39,002E,0000,02C6,6600,O00E,6100,0012 

109 DATA 4A40, 6600, 0004,60E8,4E75, 0634,0001,4000 

110 DATA 3F3C, 004F,4E41,548F,4E75,61EE,4A40, 6600 

111 DATA 0012,0039,0010,0000,02BD,6600,0080,6000 

112 DATA 002E, 5344, 6B00,00DE,9CFC, 0006, 0026, 005C 

113 DATA 66FA,6100,005E,6196,4247,1E34,4000,5247 

114 DATA 19BC,0000,4000,5347,67C0,61AE,60F8,2A7C 

115 DATA 0000,01D3,6100,015E,2A7C,0000,02C6,6100 

116 DATA 0154,6100,015E,5244,19BC,0000,4000,598E 

117 DATA 3E3C,O00D,47F9, 0000, 02C6,101B, 6700, 0008 

118 DATA 1CC0,51CF,FFF6,6100,000A,6100,FF42,6000 

119 DATA FF7C,1CFC,005C,1CFC,002A,1CFC,002E,1CFC 

120 DATA 002A,1CFC,0000,4E75,0C39,0008,0000,0E1B 

121 DATA 6600,0006,6000,004E,41F9,0000,02C6,4BF9 

122 DATA 0000,02DE,3A04,3AFC,2020,51CD,FFFA,1018 

123 DATA 6700,0006,1AC0,60F6,1AFC,0020,BBFC,0000 

124 DATA 02F8,6DF4,2039,0000,02C2,6100,OOFA,1ABC 

125 DATA 0000,2A7C,0000,02DE,6100,OOBA,6100,00C4 

126 DATA 6000,FF08,4267,4E41,2A2A,2020,2020,2044 

127 DATA 6972,6563,746F,7279,204F,7574,7075,7420 

128 DATA 2020,2053,2E44,2E20,2020,202A,2A0A,0D50 

129 DATA 6C65,6173,6520,696E,7075,7420,6472,6976 

130 DATA 6520,6065,7474,6572,2861,2D66,293A,0053 

131 DATA 7562,2D44,6972,6563,746F,7279,203A,2000 

132 DATA 613A,5C2A,2E2A,0020,2020,2020,2020,2020 


174 




Abacus 


Atari ST Disk Drives Inside and Out 


133 

DATA 

134 

DATA 

135 

DATA 

136 

DATA 

137 

DATA 

138 

DATA 

139 

DATA 

140 

DATA 

141 

DATA 

142 

DATA 

143 

DATA 

144 

DATA 

145 

DATA 


2020 , 2020 , 2020 , 2020 , 2020 , 2020 , 2020,2020 
2020,2020,2020,0000,3F3C,0001,4E41,C0BC 
0000,00FF,548F,4E75,6100,0040,303C,000A 
6100,0006,303C,OOOD,3FOO,3F3C,0002,4E41 
588F,4E75,10ID,6700,0008,6100,0012,60F4 
4E75,303C,000A,6100,0006,303C,OOOD,3F00 
3F3C,0005,4E41,588F,4E75,2F00,3F3C,0009 
4E41,5C4F,4E75,80FC,2710,4840,3F00,4840 
COBC,0000,FFFF,223C,0000,03E8,6100,000A 
301F,223C,0000,03E8,80C1,2F00,D07C,0030 
1AC0,201F,4840,COBC,0000,FFFF,82FC,OOOA 
66E6,4E75,0000,0002,061A,0A06,1016,1032 
3A0A,1C44,061E,080E,0000 


175 


Chapter Six 






Abacus 


Atari ST Disk Drives Inside and Out 


The RAM disk 


The third member of the storage media family for the Atari ST which we 
will look at is the RAM disk. Using memory to imitate the actions of a disk 
drive is an interesting, and above all, very fast method of data storage. How 
does it work? 

First, we need an area of memory that cannot be used by any other 
application running on the computer. We will put data here instead of 
writing it to a diskette. The advantage is obvious: moving data in and out of 
memory can be done very quickly and easily by the 68000 processor in the 
ST. In addition, all of the mechanical operations that slow a disk drive (head 
positioning, spin up, etc.) are avoided. The result: a RAM disk is very fast. 

What we need now is a program to manage RAM disk memory and move 
the data into memory as required. There are such programs on the market, 
and some can be found in various books on the ST (such as Atari ST Tricks 
& Tips). They all follow the same principle, which we will now examine. 

First, the memory used by the RAM disk must be initialized. A boot sector 
must be created which contains all of the information about the type, 
partitioning, and size of the RAM disk. On real disks this sector is the first 
sector on the disk, so these parameters must be written at the start of the 
RAM disk memory. 

Next, the program must install itself so that it knows whether a data transfer 
is to take place, and if so, in what direction the transfer is to go. This is 
accomplished by changing three operating system pointers to point to our 
routine. These pointers are memory locations which contain the addresses 
of programs. If the operating system wants to call such a program, it reads 
the appropriate pointer and branches to the address indicated. 

The pointers which are used for installing the RAM disk are intended for 
servicing the hard disk. They lie at memory addresses $472 to $47E and 
point to routines which have die following significance: 

Address Name Significant 

$472 hdv_bpb Determine and return the parameter block, which 

contains specifications about the diskette or hard 
disk. 

$476 hdv_rw Read/write routine for the hard disk. Data 

transfer takes place via this vector. 


179 


Abacus 


Atari ST Disk Drives Inside and Out 


Address Name Significance 

$47 A hdv_boot Boot routine for the hard disk. Not required by 

the RAM disk because it cannot be booted. 

$47E hdv mediach Determine if the medium (disk) was changed. 

Once the pointers have been changed and their old contents saved, the 
program can be exited. A special BIOS call is used to do this which allows a 
given area of memory to be reserved. The RAM disk is now installed. 

Now we have to prepare a Desktop disk icon for the RAM disk. To do this 
we click on one of the disk icons, select the menu option Install disk 
drive . . . and change the name and designator of the drive. After 
selecting OK, another icon appears on the screen. This can then be used in 
the usual manner for loading and storing data and programs. Only the 
functions Format. . . and disk copy do not work, so only individual 
files can be copied or deleted. 

Now when the operating system wants to access the hard disk or RAM 
disk, it always jumps to the RAM disk program, which is still in memory, 
via the pointers mentioned above. The RAM disk program checks to see if 
the RAM disk is being accessed or not. If not, a branch is made to the actual 
routine, whose address was saved. 

If the RAM disk is accessed, the program starts to work. For a read/write 
access, the parameters like sector, number of sectors to read, and data 
transfer direction are read from the stack and the appropriate data are copied 
into memory. If the operating system performs a "media changed" test 
(mediach), the RAM disk program returns a 0, which means that the 
medium was not changed, which of course is impossible with a RAM disk. 

The third type of call means that the operating system wants the memory 
address of the parameter block. The address is returned in register DO. 

This is all a RAM disk program does. What it can't do is retain data after the 
computer is turned off. This is the main disadvantage of this program: The 
data are not really saved, just temporarily stored. For this reason, files and 
programs that you create or modify on the RAM disk must be copied to a 
real diskette or hard disk before you turn the computer off. 

But enough of theory. Let's take a look at a RAM disk program which 
contains all of these elements. 


180 




Abacus 


Atari ST Disk Drives Inside and Out 


6.1 An easy-to-use RAM disk program 


The program listed in this chapter contains some features which really aren't 
required for the normal use of a RAM disk. But they are quite useful, and 
although they make the program somewhat longer, they also make the 
program easier to use. The program is designed for use of the RAM disk as 
drive C, but it can be easily adapted for a different drive letter. 

The program is a desk accessory, which appears in the Desk menu under 
the name ramdisk . ACC after booting. If this menu option is selected, a 
small dialog box appears which contains three options. 

The first option, which is outlined, is EXIT. If you click this button or 
press <Retum>, the box will disappear and nothing will happen. This 
button is provided in case you accidentally select the menu entry 
RAMDISK.ACC. 

The second button is labeled MORE. Clicking this button changes the 
number in the selection box on the right. This number indicates the size of 
the RAM disk to be installed. Clicking MORE will cause this number to 
increase in steps of 100 up to 800, whereupon another click will return it to 
zero. 

Once the desired RAM disk capacity has been set, click on the button with 
the number. Since the old contents of the RAM disk will be erased when a 
new memory area is installed, another dialog box appears. This contains the 
question, Erase old contents of the RAM disk? which must 
be answered with Yes, or the RAM disk's old capacity and contents will 
remain intact. 

After all of the settings have been made by selecting Yes, the program goes 
to work. It first releases the memory area which the RAM disk has 
previously occupied back to the operating system. Then the program 
attempts to reserve the desired memory area for itself. If there is not enough 
memory available, you get the message Not enough RAM. After this 
message is acknowledged, both the message and the RAM disk disappear. 
You must call the RAMDISK .ACC accessory again and choose a smaller 
RAM disk size. 

If you select zero as the capacity of the RAM disk, it will be completely 
removed and will not occupy any memory. The program can thus change 


181 


Abacus 


Atari ST Disk Drives Inside and Out 


the size of its RAM disk and install and remove it as often as desired. Most 
of the RAM disk programs on the market do not have this capability, and if 
you use RAM disks a lot you will appreciate these advantages. 

One more thing should be mentioned before we look at the program itself. 
Since a RAM disk cannot be formatted (please don't try it, because it may 
address the disk drives and accidentally format a real diskette instead), each 
file must be deleted individually in order to delete such a "disk." With this 
program, you just select the same capacity in the dialog box, and the whole 
RAM disk will be erased. 

Here is the program: 

.***** RAM-Disk with comfort S.D. ***** 


hdv bpb 

= $472 


hdv_rw 

= $476 


hdv mediach 

= $47e 


drvbits 

= $4c2 


start: 

move.1 

#nstack,a7 

;set new stack 

move 

#10,opcode 

;appl init 

move 

#0,sintin 


move 

#1,sintout 


move 

#0,saddrin 


move 

#0,saddrout 


bsr 

aes 


move 

intout,appid 

/Application ID 

move 

#77,opcode 

/graf handle 

move 

#5,sintout 


move 

#0,saddrin 


move 

#0,saddrout 


bsr 

aes 


move 

intout,grhandle /Graphic handle 

move 

#35,opcode 

/Menu Register 

move 

#1,sintin 


move 

#1,sintout 


move 

#1,saddrin 


move 

appid,intin 


move.1 

faccname,addrin 

bsr 

aes 



182 



Abacus 


Atari ST Disk Drives Inside and Out 


move intout,accid /Accessory number 
/** Here is the preparation loop ** 


ok: 


bsr 

event 

/Event_Multi 

cmp 

#40,msgbuff 

/Acc open ? 

bne 

loop 

/no 

move 

msgbuff+8,dO 


cmp 

accid,dO 

/our accessory number ? 

bne 

loop 

/ no 

bsr 

run 

/display menu 

bra 

loop 

/and again 

Selection ** 


move.1 

#howmuch,addrin 

bsr 

formalert 

/display selection 

move 

intout,choice 


cmp 

#1,choice 

/Exit? 

beq 

ende 

/yes => end 

cmp 

#3,choice 

/OK ? 

beq 

ok 

/yes 

addq 

#2,size 

/display different size 

cmp 

#18,size 

/over 800 KByte? 

bit 

more 

/ no 

clr 

size 

/no, back to 0 KByte 

lea 

sizes,aO 


clr .1 

dO 


move 

size,dO 


move 

0(aO, dO),capacit ;set new size 

lsl 

#1, dO 


lea 

deci,aO 


move.1 

0(aO,dO),offer /display new size 

bra 

run 

/repeat 

:serve : 

memory * 


move.1 

tclear,addrin 


bsr 

formalert 

/really erase it? 

cmp 

#2,intout 


beq 

okx 

/no => end 

bsr 

mf ree 

/release memory 

tst 

size 

/0 KByte ? 

bne 

okl 

/ no 


183 




Abacus 


Atari ST Disk Drives Inside and Out 


okx: 



rts 


/0 Kbyte: done 

okl: 



move 

#2,changed 

/'Disk changed' 

clr. 1 

d7 


move 

capacit,d7 

/capacity in Kbyte 

add. 1 

#9,d7 

/plus 9K for management 

asl. 1 

#5, d7 


asl. 1 

#5,d7 

/times 1024: capacity in bytes 

move. 1 

d7, -(sp) 

/RAM area to install 

move 

#$48,-(sp) 

/MALLOC function 

trap 

#1 


addq.1 

#6, sp 


tst. 1 

dO 

/error occurred ? 

beq 

terror 

/yes => error message 

move.1 

dO,buffer 

/save start address of the RAM disk 

move.1 

#init,-(sp) 


move 

#38,-(sp) 

/Initialization in Supervisor 

trap 

#14 


addq.1 

#6, sp 


rts 



terror: 



move.1 

terror,addrin 

bsr 

formalert 

/'Not enough RAM !' 

bra 

ende 

/terminate 

init: 



move.1 

hdv bpb,bpbsave /save old vectors 

move.1 

#bpb,hdv bpb 


move. 1 

hdv rw,rwsave /set vectors to new routines 

move. 1 

#rw,hdv rw 


move. 1 

hdv mediach. 

mediasave 

move.1 

#media,hdv_mediach 

move. 1 

buffer,aO 


move.1 

#10240/4,dO 


iloopl: 



clr .1 

(aO) + 

/clear boot sector and FATs 

dbra 

dO,iloopl 


; * Generate 

boot sector 

★ 

move.1 

buffer,aO 


add. 1 

#11,aO 

/at buffer+11 

lea 

boottab,al 


moveq 

#tabend-boottab-l, dO 


184 



Abacus 


Atari ST Disk Drives Inside and Out 


bloop: 

move.b (al)+,(a0)+ /copy data in boot sector 
dbra dO,bloop 

move capacit,d7 

move d7,numcl /capacity in KByte in BPB 



lsl 

#1, d7 

/capacity in sectors 



add 

#18,d7 

/plus 18 sectors 



move. 1 

buffer,aO 




add. 1 

#19,aO 

/in buffer+19 and +20 



move. b 

d7,(aO)+ 

/LO 



lsr 

#8,d7 




move. b 

d7, (aO) 

/HI 



bset 

#2,drvbits+3 

/install drive C 



rts 


/ done 


/* Function: 

Get BPB * 



bpb: 

cmp 

#2, 4(sp) 

/Drive C ? 



beq 

bpbl 

/ yes 



move. 1 

bpbsave,aO 

/old routine 



jmp 

(aO) 

/ call 


bpbl: 

move.1 

#bpbtab,dO 

/Pointer to BIOS parameter block 


rts 




/* Function: 

Read/Write * 



rw: 

cmp 

#2, 14(sp) 

/Drive C ? 



beq 

rwl 

/yes 



move.1 

rwsave,aO 

/old routine 



jmp 

(aO) 

/ call 


rwl: 

move 

12(sp),dO 

/recno, logical sector 

number 


ext. 1 

dO 




lsl.l 

#8,dO 




lsl.l 

#1, dO 

/times 512 



move.1 

6 (sp),a0 

/buffer address 



move 

10(sp),dl 

/number of sectors 



subq 

#1, dl 




move. 1 

buffer,al 

/base address 



add. 1 

dO, al 

/plus relative address 

in RAM-Disk 


move 

4(sp),dO 

/rwflag 



185 



Abacus 


Atari ST Disk Drives Inside and Out 


btst 

beq 

exg 

rloopO: move. 

rloop: move.b 
dbra 
dbra 
clr 
rts 

;* Function: 

media: cmp 
beq 
move.1 
jmp 

medial: move 
clr 
rts 


event: 

move 

move 

move 

move 

move.1 

lea 

lea 

moveq 

lopl: 

move 

dbra 

bsr 

rts 


aes: 

move.1 
move 
trap 
rts 


mfree: 

tst. 1 
beq 


#0, dO 
rloopO 
aO, al 


/read ? 

/ yes 

/exchange destination and source 


1 #511,dO 
(al)+, (aO) + 
dO,rloop 
dl,rloopO 
dO 


;one sector 
/copy buffer 

/next sector 
/OK 


Media-Change 

#2,4(sp) 
medial 

mediasave,aO 
(aO) 


/Drive C ? 

; yes 

/old routine 
/ call 


changed,dO /Diskette changed 

changed /but just once 


#25,opcode /Event_Multi, determine GEM event 

#16,sintin 

#7,sintout 

#1,saddrin 

#msgbuff,addrin 

table,al 

intin,a2 

#15,dO 

(al)+,(a2)+ /set parameters 

dO,lopl 

aes 


/ AES call 

#aespb,dl 
#$c8,dO 
#2 


/release memory 

buffer 

ende /is already removed 


186 




Abacus 


Atari ST Disk Drives Inside and Out 


move.l freinit,-(sp) 

move #38,-(sp) /reinitialization 
trap #14 ;in supervisor mode 

addq.1 #6,sp 

move.l buffer,-(sp) 

move #$49,-(sp) /MFREE function, release memory 
trap #1 
addq.1 #6,sp 

tst.l dO /error? 

beq ende /no 

move.l #errorl,addrin 

bsr formalert /error message 

ende: 

clr.1 buffer /no more memory reserved 

rts 

reinit: 

move.1 bpbsave,hdv_bpb 

move.l rwsave,hdv_rw /set vectors to old routine 

move.l mediasave,hdv_mediach 

bclr #2,drvbits+3 /remove old routine 

rts 

formalert: 

move #52,contrl /form_alert, display alarm window 

move #l,contrl+2 

move #l,contrl+4 

move #l,contrl+6 

move #0,contrl+8 

move #1,intin 

bsr aes 

rts 


table: 
accname: 

align 

howmuch: 

offer: 
clear: 

error: 

error1: 
align . 1 


dc.w $13,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0 
dc.b " RAM-Disk C ",0 

dc.b "[l][Size of RAM disk in Kbytes? ]" 
dc.b "[Exit I more I" 
dc.b " 100 ]", 0,0 

dc.b "[1) [Erase old contents I of the RAM disk?]" 
dc.b "[ Yes! | No ]", 0,0 

dc.b "[2][Not enough RAM !]" 
dc.b "[OK]", 0,0 

dc.b "[2][Error during MFREE !]" 
dc.b "[OK]”, 0,0 


187 




Abacus 


Atari ST Disk Drives Inside and Out 


capacit: 

dc.w 100 


size: 

dc.w 2 


sizes: 

dc.w 0,100,200 

,300,400,500,600,700,800 

deci: 

dc.b ' 0 100 

200 300 400 500 600 700 800' 

buffer: 

dc.l 0 

;RAM disk buffer address 

changed: 

dc.w 0 

/Flag for "disk changed" 

bpbtab: 

recsiz: 

dc.w $200 

/Sector size 

clsiz: 

dc.w 2 

/Cluster size in sectors 

clsizb: 

dc.w $400 

/Cluster size in bytes 

rdlen: 

dc.w 7 

/Directory length in sectors 

f siz: 

dc.w 5 

/FAT size 

fatrec: 

dc.w 6 

/FAT sectors 

datrec: 

dc.w 18 

/Sectors for management 

numcl: 

dc.w 1 

/capacity in Kbytes 

flags: 

dc.l 0,0,0,0 


boottab: , 

; data in 8086 

format 


dc.b 0,2 

/bytes per sector 


dc.b 2 

/sectors per cluster 


dc.b 1,0 

/reserved sectors 


dc.b 2 

/FATs 


dc.b 112,0 

/directory entries 


dc.b 2 

/sectors on media 


dc.b 0 

/media descriptor 


dc.b 5,0 

/sectors per FAT 


dc.b 9,0 

/sectors per track 


dc.b 1,0 

/sides 


dc.b 0 

/hidden 

tabend: 

align 

bpbsave: 

ds.l 1 

/Space for old vectors 

rwsave: 

ds.l 1 


mediasave 

: ds.l 1 



aespb: dc.l contrl,global,intin,intout,addrin,addrout 


bss 

choice: ds.w 1 
grhandle: ds.w 1 
appid: ds.w 1 


; data 


;Application ID 


188 




Abacus 


Atari ST Disk Drives Inside and Out 


accid: 
msgbuff: 

nstack: 

contr1: 
opcode: 
sintin: 
sintout: 
saddrin: 
saddrout: 


global: 

intin: 
ptsin: 
intout: 
ptsout: 
addrin: 
addrout: 


ds .w 1 
ds.w 16 
ds.L 128 
ds.l 1 


ds.w 1 
ds.w 1 
ds.w 1 
ds.w 1 
ds.l 1 
ds.w 5 

ds.l 8 

ds.w 80 
ds.w 80 
ds.w 80 
ds.w 80 
ds.w 80 
ds.w 80 

end 


/Accessory unit 
/NEW STACK 


/GEM parameter block 


This program was created with the AssemPro macro-assembler, which 
differs in certain respects from the DRI assembler included in the Atari 
Developer's Package. The comment lines need to be changed, which for the 
DRI assembler must start with an asterisk (*), the align instruction which 
must be even, and the bss instruction must be data for DRI. 

The program is divided into a number of parts: 

1. Installation of the accessory. 

2. Preparation loop, which in normal operation of the Atari ST runs 
constantly in the background and may therefore never end. 

3. Display and service dialog box, whereby the selected capacity is 
placed in CAPACIT. 

4. Display dialog prompt 

5. Release previously used memory (MFREE). 

6. Reserve new memory, output error message if not enough. 

7. Save BIOS vectors for the disk routines and set new vectors. 

8. GETBPB function. 

9. Read/write function. 

10. Media change function. 

11. Data fields for parameter blocks. 


189 


Abacus 


Atari ST Disk Drives Inside and Out 


Points 7 to 10 were already discussed in the previous section. A complete 
description of points 1 though 6 would be too comprehensive to take up 
here. Information on the functions used can be found in the books Atari ST 
Internals and Atari ST GEM Programmer's Reference by Abacus Software. 

Here is a BASIC loader program which creates the accessory program 
RAMDISK. ACC on the disk: 


10 

15 

20 

25 

30 

35 

40 

45 

50 

55 

60 

65 

70 

75 

80 

85 

90 

95 

100 

101 

102 

103 

104 

105 

106 

107 

108 

109 

110 
111 
112 

113 

114 

115 

116 
117 




ramdisk.acc loader 




?:fullw 2:clearw 2:gotoxy 0,0 

? "File >> a:ramdisk.acc << now being created":?:?:? 

dim c%( 735):cs#=0 

for i=0 to 735 

read a$:c%(i)=val("SH"+a$) 

check#=check#+(c%(i)) 

next i 

if check#= 4997481.92 then 70 

?"Can't go any farther;something wrong with the DATA." 
goto 80 

bsave"a:ramdisk.acc",varptr(c%(0)), 1472 
? "The program >> a:ramdisk.acc << is now written." 
?:?:?:?"Please press a key":a=inp(2):end 

I 

i********* DATA for a:ramdisk.acc ********** 

I 

DATA 601A,0000,053A,0000,0000,0000,0622,0000 
DATA 0000,0000,0000,0000,0000,0000,2E7C,0000 
DATA 0762,33FC,OOOA,0000,0766,33FC, 0000, 0000 
DATA 0768,33FC,0001,0000,076A,33FC,0000,0000 
DATA 076C,33FC,0000,0000,076E,6100,02EE,33F9 
DATA 0000,08DC,0000,053E,33FC,004D,0000,0766 
DATA 33FC,0005,0000,076A,33FC,0000,0000,076C 
DATA 33FC,0000,0000,076E,6100,O2C0,33F9,0000 
DATA 08DC,0000,053C,33FC,0023,0000,0766,33FC 
DATA 0001,0000, 0768,33FC,0001,0000,076A, 33FC 
DATA 0001,0000,076C,33F9,0000,053E,0000,079C 
DATA 23FC,0000,03EC,0000,0A1C,6100,027E,33F9 
DATA 0000,08DC,0000,0540,6100,022C,0C79,0028 
DATA 0000, 0542, 66F2,303 9,0000, 054A,B07 9, 0000 
DATA 0540,66E4,6100,0004,60DE,23FC,0000,03FC 
DATA 0000,0A1C, 6100,02BC,33F9, 0000,08DC, 0000 
DATA 053A,0C79,0001,0000,053A,6700,0276,0C79 
DATA 0003, 0000,053A, 6700,0042,5479, 0000, 04A6 


190 







Abacus 


Atari ST Disk Drives Inside and Out 


118 DATA 0C79,0012,0000,04A6,6D00,0008,4279,0000 

119 DATA 04A6,41F9,0000,04A8,4280,3039,0000,04A6 

120 DATA 33F0,0000, 0000, 04A4,E348, 41F9, 0000, 04BA 

121 DATA 23F0,0000,0000,042A,6090,23FC,0000,0432 

122 DATA 0000,0A1C,6100,024C,0C79,0002,0000,08DC 

123 DATA 6700,0010,6100,01D2,4A79,0000,04A6,6600 

124 DATA 0004,4E75,33FC,0002,0000,04E2,4287,3E39 

125 DATA 0000,04A4,DEBC,0000,0009,EB87,EB87,2F07 

126 DATA 3F3C,0048,4E41,5C8F,4A80,6700,0018,23C0 

127 DATA -0000,04DE,2F3C, 0000,01BA,3F3C, 0026, 4E4E 

128 DATA 5C8F,4E75,23FC,0000,046A,0000,0A1C,6100 

129 DATA 01E2,6000,01AE,23F9,0000,0472,0000,0516 

130 DATA 23FC,0000,0250,0000,0472,23F9,0000,0476 

131 DATA 0000,051A,23FC,0000,026A,0000,0476,23F9 

132 DATA 0000,047E,0000,051E,23FC,0000,02BA,0000 

133 DATA 047E,2079,0000,04DE,203C,0000,OAOO,4298 

134 DATA 51C8,FFFC,2079,0000,04DE,D1FC,0000,000B 

135 DATA 43F9,0000,0504,7010,10D9,51C8,FFFC,3E39 

136 DATA 0000,04A4,33C7,0000,04F2,E34F,DE7C,0012 

137 DATA 2079,0000,04DE,D1FC,0000,0013,10C7,E04F 

138 DATA 1087,08F9,0002,0000,04C5,4E75,0C6F,0002 

139 DATA 0004,6700,000A,2079,0000,0516,4ED0,2O3C 

140 DATA 0000,04E4,4E75,0C6F,0002,000E,6700, OOOA 

141 DATA 2079,0000,051A,4ED0,302F,000C,48C0,E188 

142 DATA E388,206F,0006,322F,OOOA,5341,2279,0000 

143 DATA 04DE,D3C0,302F,0004,0800,0000,6700,0004 

144 DATA C348,203C,0000,01FF,10D9,51C8,FFFC,51C9 

145 DATA FFF2,4240,4E75,0C6F,0002,0004,6700, OOOA 

146 DATA 2079,0000,051E,4ED0,3039,0000,04E2,4279 

147 DATA 0000,04E2,4E75,33FC,0019,0000,0766,33FC 

148 DATA 0010,0000,0768,33FC,0007,0000,076A,33FC 

149 DATA 0001,0000,076C,23FC,0000,0542,0000,0A1C 

150 DATA 43F9,0000,03CC,45F9,0000,079C,700F,34D9 

151 DATA 51C8,FFFC,6100,0004,4E75,223C,0000,0522 

152 DATA 303C,00C8,4E42,4E75,4AB9,0000,04DE,6700 

153 DATA 0032,2F3C,0000,036E,3F3C,0026,4E4E,5C8F 

154 DATA 2F39,0000,04DE,3F3C,0049,4E41,5C8F,4A80 

155 DATA 6700,0010,23FC,0000,0485,0000,0A1C,6100 

156 DATA 0032,42B9,0000,04DE,4E75,23F9,0000,0516 

157 DATA 0000,0472,23F9,0000,051A,0000,0476,23F9 

158 DATA 0000,051E,0000,047E,08B9,0002,0000,04C5 

159 DATA 4E75,33FC,0034,0000,0766,33FC,0001,0000 

160 DATA 0768,33FC,0001,0000,076A,33FC,0001,0000 

161 DATA 076C,33FC,0000,0000,076E,33FC,0001,0000 

162 DATA 079C,6100,FF56,4E75,0013,0001,0001,0001 


191 


Abacus 


Atari ST Disk Drives Inside and Out 


163 DATA 0000,0000,0000 

164 DATA 0000,0000,0000 

165 DATA 736B,2020,4320 

166 DATA 206F,6620,5241 

167 DATA 4B62,7974,6573 

168 DATA 6D6F,7265,207C 

169 DATA 5D5B,4572,6173 

170 DATA 656E,7473,7C20 

171 DATA 2064,6973,6B3F 

172 DATA 4E6F,205D,0000 

173 DATA 6F75,6768,2052 

174 DATA 005B,325D,5B45 

175 DATA 6720,4D46,5245 

176 DATA 0064,0002,0000 

177 DATA 0258,02BC,0320 

178 DATA 3030,2033,3030 

179 DATA 3030,2037,3030 

180 DATA 0200,0002,0400 

181 DATA 0000,0000,0000 

182 DATA 0002,0201,0002 

183 DATA 0000,0000,0000 

184 DATA 0766,0000,0770 

185 DATA 0A1C, 0000, OABC 

186 DATA 0408,0808,080A 

187 DATA 040C,0806,0E04 

188 DATA 0808,0804,OCOE 

189 DATA 0E06,0A12,OCOE 

190 DATA 0808,0806,0406 

191 DATA 0A16,0808,0808 


,0000,0000,0000,0000,0000 
, 0000,2020,5241,4D2D, 4469 
, 0000,5B31,5D5B, 5369, 7A65 
, 4D2 0, 64 69, 736B,2 069, 6E20 
, 3F20,5D5B, 457 8, 697 4,7C20 
, 2 031,3030,205D, 0000,5B31 
, 6520, 6F6C, 6420, 636F,6E74 
, 6F66,2074,6865,2052,414D 
, 5D5B,2 059, 657 3,2120,7C20 
, 5B32,5D5B,4E6F, 7420, 656E 
, 414D,2021,5D5B,4F4B,5D00 
, 7272,6F72,20 64,757 2, 696E 
, 4520,215D,5B4F,4B5D,0000 
, 0064,00C8,012C,0190,01F4 
,2020,3020,2031,3030,2032 
,2034,3030,2035,3030,2036 
,2038,3030,0000,0000,0000 
,0007,0005,0006,0012,0001 
,0000,0000,0000,0000,0000 
,7000,0200,0500,0900,0100 
,0000,0000,0000,0000,0000 
,0000,079c,0000,08DC,0000 
,0000,0002,0808,0808,08OA 
,0408,0808,0806,0406,04OA 
,0A04,080C,0A08,OA06,0808 
,0E08,2006,1004,1206,0E06 
,060C,2608,121C,3408,060A 
,0614,OEOA,0E14,040A,080A 
,0801,6204,0404,0404,0000 


When you turn your computer on and install the RAM disk, you often have 
to copy certain files to the RAM disk before you can start working. To save 
you time and effort in doing this, we have written a program that takes care 
of this for you. 


192 



Abacus 


Atari ST Disk Drives Inside and Out 


6.2 Disk to RAM disk copy 


The following program simply copies the entire contents of a single-sided 
disk to the RAM disk C. All sectors from 0 (logical sector number) to 
9*80-1 (719) are read from the selected drive and copied to the "sectors" of 
the RAM disk. You must make sure that the RAM disk has a capacity of at 
least 400K so that sector 719 also exists. 

In order to make the program as fast as possible, we read or write nine 
sectors at a time each time we call the routine FLOPRW. This speed 
advantage over copying sectors individually is supplied by the DMA chip, 
which can be programmed to read nine sectors (an entire track) at once and 
send then to the computer. The speed advantage is not tremendous, but 
every little bit helps. Naturally, it would go even faster if all of the sectors 
on the disk were read with one call, but this would produce certain memory 
size problems. 

If you use this program with a double-sided disk, all of the filenames from 
the diskette will naturally appear in the directory of the RAM disk. The 
directory is copied in its entirety, but not the other side of the disk. If the 
original disk is more than half full, the programs and files on the other side 
cannot be loaded into the RAM disk. Otherwise this program also works 
with double-sided disks. 

Let's look at the program: 


;*** Disk - 

to - RAM-Disk 

- Copy S.D. 

run: 

clr. 1 

aplrsv 


clr. 1 

ap2rsv 


clr.l 

ap3rsv 


clr. 1 

ap4rsv 


move 

#10,opcode 

;appl_init 

move 

40 ,sintin 


move 

#1,sintout 


move 

#0,saddrin 


move 

#0,sintin 


jsr 

aes 


move 

#77, opcode 

;graf handle 

move 

#5, sintout 


move 

#0, saddrin 


move 

#0, saddrout 



193 




Abacus 


Atari ST Disk Drives Inside and Out 


jsr aes 

move intout,grhandle 


move. 1 

♦alarm,dO 

bsr 

formalert 

subq 

#2, dO 

tst 

dO 

bmi 

quit 

move 

dO,drive 

clr 

sector 

loop: 

move 

drive,dl 

move 

#2, dO 

bsr 

floprw 

bne 

readerr 

move 

#2, dl 

move 

#1, dO 

bsr 

floprw 

bne 

wrerr 

add 

#9,sector 

cmp 

#9*80,sector 

bit 

loop 

quit: 

clr -(sp) 

trap #1 

floprw: 

move 

dl, -(sp) 

move 

sector,-(sp) 

move 

#9,-(sp) 

pea 

buffer 

move 

dO, -(sp) 

move 

#4,-(sp) 

trap 

#13 

add. 1 

#14, sp 

tst 

dO 

rts 

readerr: 

move.1 

freer,dO 

bsr 

formalert 

bra 

quit 


/output selection window 
;correct drive number 

/terminate 

/save drive number 
/start with sector 0 

/selected diskette 
/ read 

/read 9 sectors 
/error during read! 
/drive C = RAM disk 
/write 

/write 9 sectors 
/error during write! 

/sector number + 9 
/end ? 

/ no 


/exit => desktop 

/read/write diskette 
/drive 

/start sector 
/read/write 9 sectors 
/buffer 
/read/write 

/rwabs function 

/test for error 


/"Error during read!" 


194 




Abacus 


Atari ST Disk Drives Inside and Out 


wrerr: 

move.1 #wrer,dO 

bsr formalert ;"Error during write" 

bra quit 

aes: ;AES call 

move.1 #aespb,dl 

move #$c8,d0 
trap #2 

rts 

formalert: 
move 
move 
move 
move 
move 
move 
move.1 
jsr 
move 
rts 

alarm: dc.b "[1][Source drive to I copy from ?]" 

dc.b "[Exit| A | B 1 ", 0,0 

reer: dc.b "[2] [Error during read!] [Quit]", 0,0 

wrer: dc.b "[2][Error during write!][Quit]",0,0 

ALIGN.L 

aespb: dc.l contrl,global,intin,intout,addrin,addrout 

bss ;DATA 

contrl: /various fields for the AES 

opcode: dc.w 1 

sintin: dc.w 1 

sintout: dc.w 1 

saddrin: dc.w 1 

saddrout: dc.l 1 
dc.w 5 

global: dc.w 7 

aplrsv: dc.l 1 

ap2rsv: dc.l 1 

ap3rsv: dc.l 1 

ap4rsv: dc.l 1 

intin: dc.w 128 


#52,contrl ;form_alert 

#1,contrl+2 

#1,contrl+4 

#1,contrl+6 

#0,contrl+8 

#1,intin 

dO,addrin 

aes 

intout,dO 


195 


Abacus 


Atari ST Disk Drives Inside and Out 


ptsin: 

dc .w 

128 



intout: 

dc .w 

128 



ptsout: 

dc ,w 

128 



addrin: 

dc .w 

128 



addrout: 

dc .w 

128 



grhandle: 

dc .w 

1 



drive: 

dc ,w 

1 

/drive 

number 

sector: 

dc .w 

1 

/sector 

counter 

buffer: 

dc .w 

9*512 

/buffer 

for 9 sectors 


end 

The rather simple construction of this program makes some variations easily 
possible. For example, you can copy double-sided disks to an 800K RAM 
disk by changing the end condition in CMP #9*80, SECTOR command by 
simply inserting #9*80*2. 

Another variation would be to make the copy direction selectable. This 
would make it possible to copy the RAM disk contents back to the diskette 
when you are done working. 

It would also be interesting to convert the program into a desk accessory. 
Equipped with various additional functions, it could be a very useful tool. 

Here is the BASIC loader for the program. It creates the program 
dsktoram . prg on the diskette: 

10 i********* dsktoram loader A.S. ********* 

15 

20 ?:fullw 2:clearw 2:gotoxy 0,0 

25 ? "File >> a:dsktoram.prg << now being created":?:?:? 

30 dim c%( 279):cs#=0 

35 for i=0 to 279 

40 read a$:c%(i)=val("&H"+a$) 

45 check#=check#+(c%(i)) 

50 next i 

55 if check#= 2432944.96 then 70 

60 ?"Can't go any farther;something wrong with the DATA." 

65 goto 80 

70 bsave"a:dsktoram.prg",varptr(c%(0)), 560 

75 ? "The program >> a:dsktoram.prg << is now written." 

80 ?:?"Please press a key":a=inp(2):end 

85 


196 



Abacus 


Atari ST Disk Drives Inside and Out 


90 i********* DATA for a:dsktoram.prg ********** 

95 

100 DATA 601A,0000,01E4,0000,0000,0000,0034,0000 

101 DATA 0000,0000,0000,0000,0000,0000,42B9,0000 

102 DATA 01F4,42B9,0000,01F8,42B9,0000,01FC,42B9 

103 DATA 0000,0200,33FC,OOOA,0000,01E4,33FC,0000 

104 DATA 0000,01E6,33FC,0001,0000,01E8,33FC,0000 

105 DATA 0000,01EA,33FC,0000,0000,01E6,4EB9,0000 

106 DATA 0108,33FC,004D,0000,01E4,33FC,0005,0000 

107 DATA 01E8,33FC,0000,0000,01EA,33FC,0000,0000 

108 DATA 01EC,4EB9,0000,0108,33F9,0000,0208,0000 

109 DATA 0210,203C,0000,015A,6100,0098,5540,4A40 

110 DATA 6B00,0042,33C0,0000,0212,4279,0000,0214 

111 DATA 3239,0000,0212,303C,0002,6100,002C,6600 

112 DATA 004C,323C,0002,303C,0001,6100,001C,6600 

113 DATA 0048,0679,0009,0000,0214,0C79,02D0,0000 

114 DATA 0214,6DCC,4267,4E41,3F01,3F39,0000,0214 

115 DATA 3F3C,0009,4879,0000,0216,3F00,3F3C,0004 

116 DATA 4E4D,DFFC, 0000, 000E,4A40,4E75,203C, 0000 

117 DATA 018C,6100,001E,60CC,203C,0000,01AB,6100 

118 DATA 0012,60C0,223C,0000,01CC,303C,00C8,4E42 

119 DATA 4E75, 33FC, 0034,0000,01E4,33FC, 0001,0000 

120 DATA 01E6,33FC,0001,0000,01E8,33FC,0001,0000 

121 DATA 01EA,33FC, 0000, 0000,01EC,33FC, 0001,0000 

122 DATA 0204,23C0,0000,020C,4EB9,0000,0108,3039 

123 DATA 0000,0208,4E75,5B31,5D5B,536F,7572,6365 

124 DATA 2064,7269,7665,2074,6F20,7C20,636F,7079 

125 DATA 2066,726F,6D20,3F5D,5B45,7869,747C,2041 

126 DATA 207C,2042,205D,0000,5B32,5D5B,4572,726F 

127 DATA 7220,6475,7269,6E67,2072,6561,6421,5D5B 

128 DATA 5175,6974,5D00,005B,325D,5B45,7272,6F72 

129 DATA 2064,7572,696E,6720,7772,6974,6521,5D5B 

130 DATA 5175,6974,5D00,OOEA,0000,01E4,0000,01F2 

131 DATA 0000, 0204,0000, 0208,0000, 020C, 0000,020E 

132 DATA 0000,0002,0606,0608,0808,0808,0608,0808 

133 DATA 0806,0604,0612,0606,2408,OEOA,180C,0C10 

134 DATA 0808,0808,0806,0606,7804,0404,0404,0001 


197 




Chapter Seven 































































Abacus 


Atari ST Disk Drives Inside and Out 


Programming a disk monitor 


The programs presented thus far in this book allow you to view and modify 
some data on the diskette, but what is a disk book without a disk editor 
which you can use to view and change all of the data on the disk? Since I've 
had seven years of experience in typing in programs from magazines and 
books, I'd like to try to save you some frustration and present a quasi- 
modular construction of the program. We'll look at the program section by 
section, and this will hopefully lead to a complete program with relatively 
little typing effort. 

This listing edit. s contains all of the menu options and all of the data and 
subroutines of the entire disk editor, but only the subroutines of the sector 
menu are listed and all others routines contain just an RTS. The listing 
sub rout . s contains the subroutines which are called by the main 
program, which you can insert at the locations of the place holders in the 
program edit. s as required, and thereby gradually build the program up 
to its full power and size. 

When entering the program, your biggest problem in producing the editor 
will be the naming of labels and variables. Eight significant characters are 
simply too few for such a comprehensive assembly language project in 
order to formulate suggestive and logical names for subroutines and 
variables. 

If you want to use the editor right away, or you don't wish to type it in, it is 
also possible to order the optional diskette from Abacus which contains 
many of the programs and sources in this book (see the back of this book 
for ordering information). 


201 


Abacus 


Atari ST Disk Drives Inside and Out 


7.1 The TOS functions for disk access 


The editor functions are largely built on operating system functions (TOS or 
GEMDOS), and only a few directly access the disk controller and DMA 
chip of the Atari ST. It is possible to access these chips from various levels 
of the hierarchically-organized TOS. 

The high-level languages like Pascal, C, FORTRAN, and BASIC make it 
possible to work with sequential and random-access files, which means that 
a high-level language does not divide the disk into tracks and sectors, but 
that the disk access is file-oriented and moves only within the limits of these 
files. 

If we go one step deeper in the hierarchy of the operating system, we see 
that high-level languages use the GEMDOS functions. These GEMDOS 
functions are offered to the languages by operating-system routines, 
meaning that these GEMDOS functions are still file-oriented and offer only 
random and sequential access to files on the disk. 

At the next level we encounter the BIOS functions, which make the first real 
physical contact with the diskette possible, in which the disk is divided into 
logical sectors from 0 to the maximum possible number (1440 for 
double-sided disks, 720 for single-sided disks). The BIOS functions thus 
allow access to all sectors on the disk, but we still don't know which track 
and side the given logical sector is on. This information can be computed 
with the help of the specifications in the BIOS parameter block. If we use 
the XBIOS functions, it is possible to access tracks, sides, and physical 
sectors. The user must know how many sectors there are on a track, etc. 
The XBIOS functions offer ways of determining such disk-specific 
properties. For example, you can format individual tracks and specify the 
desired number of sector per track. 

The center of all routines are the WD1772 disk controller and the DMA 
chip, which occupy I/O addresses in the range $FF800 to $FFFFF. 

For example: The BASIC command WRITE#, which writes data to a 
sequential file, uses the GEMDOS function WRITE, which in turn calls the 
BIOS function RWABS, which makes use of the XBIOS function 
FLOPWR, which finally tells the DMA and controller chips where and what 
to write on the disk. 


202 


Abacus 


Atari ST Disk Drives Inside and Out 


All operating system functions (GEMDOS, BIOS, XBIOS) are described in 
detail in the Abacus book Atari ST Internals, so we will discuss only the 
eight BIOS and XBIOS calls which directly communicate with the disk. All 
of the calls expect their parameters on the stack, and return results or a 
negative error code in the case of an error in the register DO. Registers 
D0-D2 and A0-A2 are often changed after a call, and so must be saved if 
their contents are required. The two BIOS functions RWABS and GETBPB 
are called via the BIOS specific TRAP #13 and perform the following: 

RWABS: BIOS function number 4 

This very flexible function is used to both read from and write to one or 
more logical sectors. These sectors can be on a physical diskette, the hard 
disk, or even a RAM disk. The following parameters are passed to it: 

device: determines the drive which will be accessed. The numbering 
starts with 0 for drive A and has no upper limit. The RAM disk 
presented in section 6.1 of this book is addressed as drive C, so 
it would have device number 2. 

recnr: specifies the logical number of sector to be processed. 

Numbering again starts at 0. The maximum number of sectors 
varies depending on the device: 720 logical sectors fit on a 
single-sided 80 track diskette in Atari format (double density), 
of which "only" 702 are available for user data. TOS uses the 
remaining 18 sectors to manage the user data with the directory 
and FAT (File Allocation Table). 

number: the number of logical sectors to be processed. 

buffer: an address from which or to which the data is to be written. If 
you want to read 4 logical sectors of the Atari-specific format 
(512 bytes/sector), there must be 4*512=2048 bytes available at 
this address. 

rwflag: determines whether the function will write to or read from the 
disk. Four possible values are possible: 

rwflag: Me aning! 

0 Read sectors 

1 Write sectors 

2 Forced read sectors (even if disk changed) 

3 Forced write sectors (even if disk changed) 


203 



Abacus 


Atari ST Disk Drives Inside and Out 


A possible call in machine language could look like this: 


move.w 

r- 

fd 

l 

o 

=#= 

* 

drive A (device) 

move.w 

#11,-(a7) 

•k 

recnr start at logical sector 11 

move.w 

#5, -(a7) 

k 

number, all 5 directory sectors 

move.1 

#buffer,-(a7) 

k 

address of free space 

move.w 

#2,-(a7) 

k 

rwflag, forced read 

move.w 

#4, -(a7) 

★ 

BIOS function number 

trap 

#13 

* 

BIOS call 

add. 1 

#14,a7 

k 

restore stack 

tst. w 

dO 

★ 

check if error occurred 

bmi 

error 

* 

negative value means error 

. . . 


★ 

continue here for no error 



k 

the data read is now in 

. . . 


★ 

RAM at the address "buffer" 


GETBPB: BIOS function number 7 

The BIOS parameter block contains the data about the current disk. These 
data are found in the boot sector of the diskette and are placed into the BPB 
(BIOS Parameter Block) in RAM by this function. Assembly language call: 


move.w 

device,-(a7) 

★ 

drive 0 = A 

move.w 

#7,-(a7) 

★ 

BIOS number 

trap 

#13 



addq.1 

#4,a7 

★ 

clean up stack 

tst .w 

dO 



bmi 

error 

★ 

dO negative if error 



★ 

else DO contains the addr of the 



k 

Normally this is $4DCE for drive 



k 

and $4DEE for drive B 


At the address returned in DO you will find the data in word (2-byte) 
quantities: 

Drive A 


Address: 

Name; 

Meaning: 


PS 

$4DCE 

recsiz 

sector size in bytes 

512 

512 

$4DD0 

clsiz 

cluster size in sectors 

2 

2 

$4DD2 

clsizb 

cluster size in bytes 

1024 

1024 

$4DD4 

rdlen 

directory length in sectors 

7 

7 


204 






Abacus 


Atari ST Disk Drives Inside and Out 


Address;, 

Name: 

Meaning; 

SS. 

ns 

$4DD6 

fsiz 

FAT size in sectors 

5 

5 

$4DD8 

fatrec 

sector number in the second FAT 

6 

6 

$4DDA 

datrec 

sector number of the first data cluster 

18 

18 

$4DDC 

numcl 

number of clusters on the disk 

351 

711 

$4DDE 

bflags 

various flags 



$4DE0 


unknown 



$4DE2 

nside 

number of sides on disk 

1 

2 


The data shown apply for the Atari-specific recording format with 80 tracks 
(SS = single-sided, DS = double-sided). 

MEDIACH: BIOS function number 9 

This function uses the disk name to see if the disk has been changed. The 
drive number is passed as the parameter. 


move.w device,-(a7) 
move.w #9,-(a7) 
trap #13 
addq.1 #4 , a7 


* drive number 

* BIOS function number 

* call 

* restore stack 


The value passed back in DO is between 0 and 2 and has the following 
meaning: 


Number: Meaning; 

0 Disk was not changed 

1 Disk might have been changed 

2 Disk was changed 

Here are the four XBIOS functions which are important for our purposes. 

FLOPRD: XBIOS function number 8 

With this function you can read one or more consecutive sectors on a track. 

The parameters to be passed are: 

number: determines how many sectors are to be read. The possible 
values for the Atari format vary from one to ten. Ten sectors can 
be read only if a special program is used to format the disk, 
because the Atari format program writes only nine sectors per 
track on the disk. 


205 



Abacus 


Atari ST Disk Drives Inside and Out 


side: specifies the side of the disk, 0 or 1. 

track: determines the track on which the sectors are located, 

sector: the physical sector itself, 
device: the drive parameter (0=A). 

filler: a meaningless longword, probably intended for later expansion, 

buffer: the address to which the data are to be transferred. 


move.w 

#1,-(a 7) 

k 

number, one sector 

move.w 

#0,-(a7) 

k 

side 

move.w 

#0, -(a7) 

* 

track zero 

move.w 

#1, -(a7) 

* 

sector one = boot sector 

move.w 

#0,-(a7) 

* 

drive A 

move.1 

#0,-(a7) 

★ 

filler, dummy long word 

move.1 

♦buffer,- (a7) 

* 

address of the data destination 

move.w 

#8,-<a7) 

k 

XBIOS function number 

trap 

#14 



add. 1 

#20,a7 



tst. w 

dO 



bmi 

error 



ds .b 

512 




FLOPWR: XBIOS function number 9 

The counterpart of the previous function, FLOPWR is used to write sectors 
to the disk. The parameters to be passed are the same as for FLOPRD. 


buffer: 


move.w 

#4, -(a7) 

★ 

number, four sectors 


move.w 

#0,-(a7) 

k 

side 


move.w 

#5,-(a7) 

k 

track five 


move.w 

#1, -(a7) 

k 

sector one = start sector 

for writ 

move.w 

#0,-(a7) 

★ 

drive A 


move.1 

#0, -(a7) 

* 

filler, dummy long word 


move.1 

♦buffer,-(a7) 

* 

address of the data to be 

written 

move.w 

#9,-<a7) 

★ 

XBIOS function number 


trap 

#14 




add. 1 

#20,a7 




tst. w 

dO 




bmi 

error 




ds .b 

4*512 





206 


Abacus 


Atari ST Disk Drives Inside and Out 


This call writes the 2048 bytes which are located in memory at address 

buffer to the sectors 1, 2, 3, and 4 of track 5 on side 0 of the disk. 

FLOPFMT: XBIOS function number 10 

This routine makes it possible to format a track with 1-10 sectors per track. 

The parameters are: 

virgin: determines the contents of new sectors; this data will be placed 

in the individual sectors. The same value that TOS uses 
($E5E5) should be used. Byte values greater than $EF should 
not be used under any circumstances because these represent 
special functions and will cause things like address marks or 
checksums of the previous data to be written. 

magic: the magic constant $87654321. 

interleave: determines the sector interval on the disk. Computers with 
disk controllers without DMA must evaluate data read from 
disk, which takes some time. This can cause the next sector to 
rotate past the read/write head before the CPU is done. If the 
sectors are written in some order other than 123456789 
(interleave =1), line 162738495 (interleave = 2), the time 
between the current and next sectors is sufficient for the data 
evaluation. This can speed the transfer quite a bit because 
otherwise the disk would have to turn one complete revolution 
in order to find the next sector. On the ST the data evaluation is 
handled by the controller, so sectors can be written without an 
interleave. A value of one should be passed here. 

side: the disk side 

track: the destination track 

spt: number of sectors per track. The disk can have ten sectors per 

track, TOS works with nine. 

device: drive number 

filler: another dummy longword for later expansion 

buffer: determines the address at which the XBIOS constructs the 

complete track. About 8K of memory is required. 


207 



Abacus 


Atari ST Disk Drives Inside and Out 


move.w 

#$e5e5,- 

(a7) * 

virgin 

move.w 

#$87654321,-(a7) * 

magic 

move.w 

#1, -<a7) 

★ 

interleave equals 1 

move.w 

#0, -(a7) 

★ 

side 0 

move.w 

#5,-(a7) 

★ 

track 5 

move.w 

#9,-(a7) 

★ 

spt, 9 sectors per track 

move.w 

#0, -(a7) 

★ 

device 0 equals drive A 

move.1 

#0, -(a7) 

★ 

filler, dummy long word 

move.1 

#buffer. 

-<a7) * 

address of the free space 

move.w 

#10,-(a7 

) * 

XBIOS function number 

trap 

#14 



add. 1 

#26,a7 



tst. w 

dO 

★ 

error occurred? 

bmi 

error 

★ 

yes 

ds ,b 

8*1024 

★ 

space for track 


PROTOBT: XBIOS function number 18 

This function makes it easier to create a boot sector for various disk 
formats. First you read sector 1 of track 0, side 0 of a arbitrarily formatted 
disk, call PROTOBT, and then write the boot sector with PROTOBT 
modified back to sector 1, track 0, side 0 of the disk on which the boot 
sector is to be created. The parameters to be passed: 

exec flag: indicates whether the boot sector is executable, that is whether 
there is an executable boot program at byte 30 relative to the 
start of the sector. Possible values are: 


Value; 

o 

l 

-l 


Meaning; 
not executable 
executable 

buffer stays the way it was 


disktvpe: 

0 40 track, single-sided (SS, SD 180K) 

1 40 track, double-sided (DS, SD 360) 

2 80 track, single-sided (SS, DD 360) 

3 80 track, double-sided (DS, DD 720) 

-1 Disk type remains unchanged 

The Atari formats, as we have already mentioned, are the 
double-density formats 2 and 3. 


208 


Abacus 


Atari ST Disk Drives Inside and Out 


serialnr: the serial number is a 24-bit number which is written in the 
boot sector and is used by the operating system to detect when 
the disk has been changed. If the serial number passed is 
greater than 24 bits (such as $01000000), the operating system 
will write a random number. If it is -1, the buffer serial number 
will not be changed. 

buffer: the address at which the boot sector is located (512 bytes). 


move.w 

#-l,-(a7) 

★ 

execflag, don't change executability 

move.w 

#3, -(a7) 

* 

disk type, 80 track, double-sided 

move.1 

#buffer,-(a7) 

* 

location of sector 

move.w 

#18 

★ 

XBIOS function number 

trap 

#14 



add. 1 

#14,a7 



tst .w 

dO 



bmi 

error 

★ 

didn't work 


buffer: ds.b 512 

This program fragment converts a boot sector from a single-sided disk to 
one for a double-sided disk, which can then be written on the second 
formatted side of the disk. 

Now let's take a look at the information found in the boot sector. 

The 16-bit data are stored in Intel format (first low byte, then high byte) on 
the disk, and an executable boot sector is indicated by a checksum of 
$1234. 


Bvte 

0,1 

2-7 

8-10 

11-12 

13 

14-15 

16 

17-18 

19-20 

21 


40 track SS 40 tr PS 80 tr _££ 80 tr D£ 

bra 30 Jump to $30 if the boot sector is executable 

Text: 'Loader' 

serialnr 


bps 

512 

512 

512 

512 

spc 

2 

2 

2 

2 

res 

1 

1 

1 

1 

fat 

2 

2 

2 

2 

dir 

64 

112 

112 

112 

sec 

360 

720 

720 

1440 

media 

252 

253 

248 

249 


209 


Abacus 


Atari ST Disk Drives Inside and Out 


Bvte 


40 track SS 4 

22-23 

spf 

2 

24-25 

spt 

9 

26-27 

side 

1 

28-29 

hide 

0 

30 

bootcode: boot code for a 


lr„PS 8 0 tr SS 80 tr PS 


2 5 5 
9 9 9 
2 1 2 
0 0 0 


executable sector 


510-511 checksum of the entire boot sector from bytes 0 to 509 


7.2 Listing and operation of the disk editor 


As mentioned before, here is the first part of the disk editor. This listing is 
written for the Abacus AssemPro assembler package. After you have 
typed in the listing correctly and assembled the program, only the sector 
menu works in the program edit.tos. To complete the program, you 
must replace the "dummy subroutines" with the working versions of the 
routines, which we shall introduce later on in this chapter. 

.********************************************************************* 

;* 

/* The little disk editor, U. Braun , August 1986 * 

• * 

f * 

!* ATARI ST DISK DRIVES INSIDE AND OUT * 

;* * 

.***********t********** t **t**********j,, (ti *** lttj[ttitlj[]t j )ttil)ltsli)tlit)t 


text 


;*********************************************************************** 
• ★ 

/ * 

;* Entry after loading, calculate length, and reserve space * 

;* * 

.*****************i*******t**************t**t******* t * J[( 1 ** ( , tjlU(I , 41 tt j H 

sstart: move.l a7,a5 ;* base address on the stack 


move. 1 

4(a5) , a5 

• ★ 

/ 

basepage address = start of program - 

move.1 

$c(a5),dO 

• ★ 

/ 

program length 

add. 1 

$14(a5),dO 

• ★ 

/ 

length of the initialized data area 

add. 1 

$lc(a5),dO 

• ★ 

length of the uninitialized data area 

add. 1 

#$1100,dO 

• * 
r 

4 K userstack=sufficient space 

move. 1 

a5,dl 

• ★ 
r 

start address of the program 


210 


Abacus 


Atari ST Disk Drives Inside and Out 


add. 1 

dO, dl 

• ★ 
f 

plus number of occupied bytes = 



• * 

/ 

space requirement 

and.l 

#-2,dl 

• •k 
r 

even address for stack 

move. 1 

dl, a7 

• * 

/ 

user stack pointer to last 4K 

move. 1 

dO, - (sp) 

• ★ 
r 

length of reserved area 

move. 1 

a5, - (sp) 

• * 

/ 

start address of the reserved area 

move .w 

dO, - (sp) 

• * 

§ 

dummy word 

move.w 

#$4a,-(sp) 

• * 
r 

GEMDOS function SETBLOCK 

trap 

#1 



add. 1 

#12,sp 

• * 
r 

restore old stack address again 

jsr main 

• * 
r 

jump to main program. ( user-created 

move.1 

#0, - (a7) 

• ★ 

/ 

ends the current program 

trap 

#1 

• ★ 
r 

back to GEM desktop 


********************************************************************** 
★ ★ 

* This is the start of the actual program * 

★ ★ 
★ ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★•A:***** 


main: 

jsr 

startl 

★ 

initialize line-A 


jsr 

emptybuf 

★ 

empty keyboard buffer 


jsr 

clear 

★ 

clear screen 


jsr 

init 

★ 

set default parameters 


jsr 

gomain 

★ 

go to main menu 


jsr 

menull 

★ 

pass control to menu handler 

mainend: 

rts 


★ 

return to desktop 

•★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A******** 

init: 

jsr 

cursoff 

★ 

turn cursor off 


jsr 

clear 

★ 

clear screen 


move. w 

#0,wtrack 

•k 

track zero, side zero 


move. w 

#0,wside 




move. w 

#0,wdrive 

★ 

drive zero, sector one 


move, w 

#l,wsector 

★ 

set 


move. w 

#0, dO 




move. w 

#6,maxdriv 

* 

max number of drives 


move. w 

#l,maxside 

* 

max number of sides-1 


move. w 

#79,maxtrack 

* 

default max number of tracks 


move. w 

#9,maxsect 

* 

default max sectors 


move. w 

#9,asector 

★ 

max number of sec/track 


move. b 

#'0 1 ,setrack 

★ 

put correct values in 


move. b 

#'9',setrack+1 

★ 

menus 


move. w 

#1500,maxclust 

★ 

max number of clusters 


MOVE. L 

#spacetr,EDITPTR 

★ 

BUFFER 


jsr 

prmessag 

★ 

output message 


211 








Abacus 


Atari ST Disk Drives Inside and Out 


rts 


;* and return 


;* Output message with copyright * 

•**★*★★**★★**★*★★*★★*★**★*★★★★**★*★★★★★★*★*★*★★**★★*★★★★★★*★**★★★★*★* 


prmessag 


jsr 

emptybuf 

move. w 

#20,column 

move.w 

#10,line 

jsr 

loccurs 

move.1 

#hafragl,aO 

jsr 

printf 

move.w 

#20,column 

move.w 

#12,line 

jsr 

loccurs 

move.1 

#hafrag2,aO 

jsr 

print f 

move.w 

#20,column 

move.w 

#14,line 

jsr 

loccurs 

move.1 

#hafrag3,aO 

jsr 

printf 

jsr 

wkey 

jsr 

clear 

jsr 

emptybuf 

rts 



;* empty keyboard buffer 
;* position cursor 

;* message part 1 
;* output 


;* position cursor 
;* message part 2 
;* output 

;* position cursor 

;* message part 3 

;* output 

;* wait for a key 

;* clear screen 

;* empty keyboard buffer 

;* and return 


.********************************************************************* 

r 

;* This is the menu loop, the part of the program that controls * 

;* the whole program. Here we check to see if a different menu * 

;* option was selected by cursor right or left, or a menu option * 

;* is selected with cursor up and down. If so, control is passed * 

;* to these menu options by means of meselct. * 

.********************************************************************* 

r 


menu11: 

jsr 

key 

• ★ 
f 

read keyboard 


tst . 1 

dO 

• ★ 
t 

no input, keep waiting 


beq 

menull 




swap 

dO 

• ★ 

/ 

else check for various keys 


cmp.b 

#$44,dO 

• ★ 
t 

F-10 key = end, NOTSTOP, for Debug 


beq 

menend 



menul2 : 

cmp.b 

#$4b,dO 

• * 

/ 

cursor left 


bne 

menul3 




jsr 

curleft 




bra 

menull 




212 




Abacus 


Atari ST Disk Drives Inside and Out 


menul3: 

cmp. b 

#$4d,dO 

;* cursor right 


bne 

menul4 



jsr 

curright 



bra 

menull 


menul4: 

cmp. b 

#$50,dO 

;* cursor down 


bne 

menul5 



jsr 

cursdown 



bra 

menull 


menul5: 

cmp. b 

#$48,dO 

;* cursor up 


bne 

menul6 



jsr 

cursup 


menul6: 

bra 

menull 


mainend2 

!: add.1 

#8,a7 

;* two return addresses 

menend: 

rts 


;* (remove) 


still on the stack 


********************************************************************** 

* A menu option is selected with cursor up, the corresponding * 

* jump address block is loaded from jmptable, and control branches * 

* to mselect. * 




cursup: move.1 incvar,jmptable 

jsr meselect 

rts 


;* jump table for selection by 
;* cursor up, execute routine 
;* and back to menu loop 


********************************************************************** 

* A menu option was selected with cursor down, in some menus the * 

* subroutine to be executed is determined by the selecting key * 

* (up or down), such as inctrack and dectrack on the sector menu. * 

********************************************************************** 


cursdown: move.l decvar,jmptable 

jsr meselect 

rts 


;* jump table for selection 
;* by cursor down 




* The user "travels" through the individual menu options with the * 

* cursor left key and they are displayed in reverse. * 

*********************************************************************** 


213 







Abacus 


Atari ST Disk Drives Inside and Out 


curleft: 

move. 1 

revnum, dO 


sub. 1 

I-* 

a 

o 


beq 

laround 


move.1 

dO,revnum 


bra 

curlend 

laround: 

move. 1 

ganz,revnum 

curlend: 

jsr 

dispmen 


rts 



;* selection of menu options 
;* write in reverse 

;* swap around 
;* display the menu 


* as curleft, except for cursor right * 


curright: 

move. 1 

revnum,dO 


add. 1 

#1, dO 


cmp. 1 

ganz,dO 


bgt 

raround 


move.1 

dO,revnum 


bra 

currend 

raround: 

move.1 

#1,revnum 

currend: 

jsr 

rts 

dispmen 


;* as for curleft 


********************************************************************** 

* Execute the appropriate subroutine * 

********************************************************************** 


meselect: 


jsr 

emptybuf 

• ★ 
t 

move.1 

jmptable,aO 

• * 
/ 

move.1 

revnum,dO 

• ★ 
r 

subq. 1 

=#= 

M 

a 

o 

• ★ 
f 

lsl.l 

#2, dO 

. * 
r 

move.1 

(aO, dO . 1) , al 

• ★ 
/ 

jmp 

(al) 

• ★ 
r 


Call the selected routine 
the jump table contains 
the start address of the 
jump address block 
times four, one address 
occupies four bytes, load 
and execute the routine 


******************************************************************** 

* Error handler: an error string is obtained from the negative * 

* error number passed on the stack, and this error string is then * 

* displayed. * 

******************************************************************** 


errhand: 


move. w 

#10,column 

move. w 

#2,line 

jsr 

loccurs 

jsr 

delline 

move. w 

4(a7),dO 


;* the error number is 
;* on the stack (word) 
;* position cursor in 
;* delete line 
;* get error number 


passed 
line 2 


214 








Abacus 


Atari ST Disk Drives Inside and Out 


neg .w 

dO 

cmp .w 

#29,dO 

bit 

errhandl 

move.w 

#2 9, dO 

lsl. w 

#2, dO 

move.1 

ferrtab,al 

move.1 

0(al,dO.w),aO 

jsr 

printf 

jsr 

wkey 

jsr 

delline 

jsr 

cursbuf 

move.1 

(a7)+,aO 

addq.1 

#2,a7 

jmp 

(aO) 


;* make positive 
;* compare with max error 

;* default error number 

;* use as pointer in 

;* the error table 

;* get error string 

;* print it 

;* wait for keypress 

;* delete line again 

;* cursor back to line 4 

;* get return address 

;* correct stack (error #) 

;* back to caller 


*★***★★★**★★*★*★★★★★★★★★★*★★**★★*★★★**★*★***★*★★★**★**★*★**★★**★*★*★★★ 

* Passes the parameters for the main menu to the various variables * 

* menuadr, incvar, decvar, ganz, revnum * 

★**★★★**★★*★★★★★**★★*★*★★★★*★★*★******★**★**★★*★★★★★***★*★★***★*★★★*★★ 


gomain: 


jsr 

clear 

• ★ 
r 

move.1 

#7,ganz 

• * 
r 

move. 1 

#1,revnum 

• * 
r 

move.1 

#menmain,menuadr 

• ic 
f 

move.1 

thaincjmp,incvar 

• * 
/ 

move. 1 

#haincjmp,decvar 

• ★ 
r 

jsr 

dispmen 

• ★ 
r 

rts 


• ★ 
t 


clear the screen 
seven options in mani menu 
invert first option 
addresses of the menu strings 
address of the menu routines 
same for cursor up and down 
display menu 
and return 


★****★★*★★***★**★**★***★★**★*******★*★★★*★★*★★*★★**★★★*★***★****★★*★★★ 
* Here are the main menu routines * 


********************************************************************** 

* supplies the variables of the menu-select system with the * 

* addresses for the TRACK menu point * 

********************************************************************** 


gotrack: 


jsr 

clear 

move. 1 

tmentrack,menuadr 

move. 1 

#8,ganz 

move. 1 

#5,revnum 

move.1 

#trincjmp,incvar 

move.1 

ttrdecjmp,decvar 

jsr 

dispmen 


* clear screen 

* addresses of the menu strings 

* the track menu has 8 options 

* invert 5th option 

* Cursor-up jump table 

* Cursor-down jump table 

* display menu 


215 









Abacus 


Atari ST Disk Drives Inside and Out 


jsr cursmess ;* and output a message 

move.l #trfragl,aO ;* "TRACK MODE" 

jsr printf 

rts ;* Return to menu 

• ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■St** 
r 

;* supplies the variables of the menu-select system with the * 

;* addresses for the TRACK with SYNC menu point * 

r 


gosync: move.l 
move.1 
move. 1 
move.1 
move. 1 
jsr 
jsr 

move.1 

jsr 

rts 


#6,ganz 
#4,revnum 
#syincjmp,incvar 
#sydecjmp,decvar 
tmensync,menuadr 
dispmen 
cursmess 
#trfrag2,aO 
printf 


* Track with SYNC menu 

* has six menu options 

* up jump table 

* down jump table 

* addresses of the menu strings 

* display the menu 

* position cursor 

* "Track with Syncs" 

* print 


*********************************************************************** 

r 

;* supplies the variables of the menu-select system with the * 

;* addresses for the SECTOR menu point * 

.*********************************************************************^ 

/ 


jsr 

clear 


move.1 

#mensect,menuadr 

;* sector menu options 

move. 1 

tseincjmp,incvar 


move.1 

#sedecjmp,decvar 


move. 1 

tspacetr,editptr 


move. 1 

#8,ganz 

;* 8 options 

move.1 

#5,revnum 

;* display 5th in reverse 

jsr 

dispmen 


jsr 

cursmess 


move.1 

#sefragl,aO 


jsr 

printf 


rts 




.★★★★★★★★a************************************************************* 

r 

;* supplies the variables of the menu-select system with the * 

;* addresses for the CLUSTER menu option * 

*********************************************************************** 

r 

goclust: jsr initdriv ;* cluster menu, initialize 

jsr rdfat ;* first drive, then read FAT 


216 





Abacus 


Atari ST Disk Drives Inside and Out 


move.1 

#8,ganz 

• * 
r 

menu has 8 subpoints 

move.1 

#3,revnum 

• ★ 
r 

read = reverse 

move.1 

#menclust,menuadr 

• ★ 
r 

address of the menu string 

move.1 

#clincjmp,incvar 

• ★ 
r 

jump table 

move.1 

#cldecjmp,decvar 



jsr 

cursmess 



move.1 

#clfragl, aO 

• ★ 
t 

"cluster mode" 

jsr 

printf 

. * 

! 

write 

jsr 

dispmen 

• ★ 
r 

display menu and 

rts 


• ★ 
r 

return 


•★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★it******* 

;* supplies the variables of the menu-select system with the * 

;* addresses for the FORMAT menu option * 

•********************************************************************** 

goformat: jsr clear ;* format menu 

move.l tformmen,menuadr ;* address of the menu string 

move.l #8,ganz ;* eight menu options 

move.l #3,revnum ;* third in reverse 

move.l #foincjmp,incvar 

move.l Ifodecjmp,decvar 

jsr dispmen 

jsr cursmess 

move.l #drfragl,aO 

jsr printf 

rts 


* Submenu for the FORMAT menu, supplies the variables with the * 

* addresses of the GAP menu * 

* ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★TIT* 


gogaps: jsr clear 

move.l #mengap,menuadr 

move.l #7,ganz ;* seven menu options 

move.l #l,revnum 

move.l #gpincjmp,incvar 

move.l #gpdecjmp,decvar 

jsr dispmen 

jsr cursmess 

move.l #gpfragl,aO 

jsr printf 

rts 


217 







Abacus 


Atari ST Disk Drives Inside and Out 


.★*★****★*************★****★********★****★*★★****★★**★************★***★★ 
r 

;* supplies the variables of the menu-select system with the * 

;* for the OPTION menu option * 

•***★★*★**★******★*★★★****★*★**★*★****★★***★****★*★★*★*★**************** 

r 


goinit: 


move. 1 

#6,ganz 

move. 1 

#4, revnum 

move. 1 

#inincjmp,incvar 

move. 1 

#indecjmp,decvar 

move. 1 

fmeninit,menuadr 

jsr 

dispmen 

jsr 

cursmess 

move.1 

#drifragl,aO 

jsr 

printf 

rts 



;* init menu has six 
;* options 


.*********************************************************************** 

t 

;* Here follow the first routines of the SECTOR menu * 

.***********★*********★***★********★****************************★******* 

r 

.*************************************★*★★*****************★************ 

/ 

;* Increments the drive number within the menu option * 

.****************************★****************************************** 

r 


incdrive: 

move. w 

wdrive, dO 


cmp.w 

maxdriv,dO 


bit 

incdrl 


move.w 

#0, dO 


bra 

incdr2 

incdrl: 

addq. w 

#1, dO 

incdr2: 

move.w 

dO,wdrive 


add.b 

#'0',d0 


move.b 

d0,mdrive 


jsr 

rts 

dispmen 


;* compare active drive 
;* with maxdrive 
;* if smaller, then increment 
;* else active drive to zero 

;* store again 

;* and enter in menu 

• ★ 
r 

;* display it 
;* and return 


.*★***★★★*★★★★*★★*★**★*★★***★*************★***************************** 

/ 

;* Decrements the drive number within the menu option, the following * 

;* subroutines work like inctrack, incside * 

.*********************************************************************** 

r 


decdrive: 

move.w 

wdrive,dO 


cmp.w 

=#= 

O 

a 

o 


ble 

decdrl 


subq. w 

#1, dO 


bra 

decdr2 

decdr1: 

move.w 

maxdriv,dO 

decdr2: 

move.w 

dO,wdrive 


;* decrement current drive 


218 




Abacus 


Atari ST Disk Drives Inside and Out 


add.b 

#'0',dO 

move.b 

dO,mdrive 

jsr 

dispmen 

rts 



incside: 

move.w 

wside,dO 

;* current side 


cmp. w 

#1, dO 

;* equal to one? 


bit 

incsil 

;* if so, then 


move.w 

#0, dO 

;* set side zero 


bra 

incsi2 


incsil: 

move. w 

#1, dO 

;* else side one 

incsi2: 

move.w 

dO,wside 

;* and store 


add.b 

#'0',d0 

;* and enter in menu string 


move. b 

dO,mside 



jsr 

dispmen 

;* display menu 


rts 


;* and return 

decside: 

move. w 

wside,dO 

;* decrement side 


cmp. w 

#0, dO 



ble 

decsil 



move.w 

#0, dO 



bra 

decsi2 


decsil: 

move.w 

#l,d0 


decsi2: 

move.w 

dO,wside 



add.b 

# 1 0',dO 



move.b 

dO, mside 



jsr 

dispmen 



rts 



; ********************************************,*******************. 

inctrack: 

move.w 

wtrack,dO 

;* increment track, compare 


cmp. w 

maxtrack,dO 

;* current with maxtrack 


bit 

inctrl 

;* if smaller, then continue 


move.w 

#0, dO 

;* else current track to zero 


bra 

inctr2 


inctrl: 

addq.w 

#1, dO 

;* add one 

inctr2: 

move.w 

dO,wtrack 

;* and store 


ext. 1 

dO 



divu 

#10,dO 

;* enter in menu 


add.b 

#■0■,d0 

;* binary -> ASCII 


move.b 

dO,mtrack 

;* high byte 


swap 

dO 

f 


add.b 

#'0',dO 



move.b 

dO,mtrack+1 

;* low byte 


219 







Abacus 


Atari ST Disk Drives Inside and Out 



jsr 

rts 

dispmen 

dectrack: 

move. w 

wtrack,dO 


cmp.w 

#0, dO 


ble 

dectrl 


subq.w 

#1, dO 


bra 

dectr2 

dectrl: 

move.w 

maxtrack,dO 

dectr2: 

move.w 

dO,wtrack 


ext. 1 

dO 


divu 

#10,dO 


add.b 

# • 0 • ,d0 


move.b 

dO,mtrack 


swap 

dO 


add.b 

# ' 0 ' ,d0 


move.b 

dO,mtrack+1 


jsr 

rts 

dispmen 

• ********************** 

incsect: 

move.w 

wsector,dO 


cmp. w 

maxsect,dO 


bit 

incsel 


move.w 

#0, dO 


bra 

incse2 

incsel: 

addq.w 

#1, dO 

incse2: 

move.w 

dO,wsector 


ext. 1 

dO 


divu 

#10,dO 


add.b 

o 

a 

o 


move.b 

d0,msector 


swap 

dO 


add.b 

O 

O 


move. b 

d0,msector+l 


jsr 

rts 

dispmen 

decsect: 

move. w 

wsector,dO 


cmp.w 

#0, dO 


ble 

decsel 


subq.w 

#1, dO 


bra 

decse2 

decsel: 

move. w 

maxsect,dO 

decse2: 

move. w 

dO,wsector 


ext. 1 

dO 


;* display menu 

;* decrement track 
;* current track equals zero 


;* then current track = maxtrack 


;* enter in menu string 
;* display and back 

********************************** 

;* increment current sector 
;* see inctrack 


;* decrement current sector 


220 




Abacus 


Atari ST Disk Drives Inside and Out 


divu 

#10,dO 

add.b 

#'0',d0 

move.b 

dO,msector 

swap 

dO 

add. b 

=#= 

o 

a 

o 

move.b 

dO,msector+1 

jsr 

dispmen 

rts 



*********************************************************************** 

* Reads the current sector, in wsector, if drbyte = 1024 then 1024 * 

* bytes will be read, because the operating system calculates the * 

* bytes to be read from the number of sectors by multiplying the * 

* number of sectors by 512. If you pass 2 sectors, then 1024 bytes * 

* will be read, regardless of whether they are organized as one * 

* sector of 1024 bytes, or 2 of 512 bytes, or 4 of 256 bytes. * 

*********************************************************************** 


;* number of bytes/sector 
;* default equals 1 sector 
;* if drbyte = 1024, then 
;* read one sector of 1024 bytes 

;* number of sectors 
;* side 
;* track 

;* sector, or start sector 
;* drive 

;* dummy long word 
;* buffer address 
;* floprd 


readsec: move.w 
move.w 
cmp.w 
bne 

move. w 

readweit: move.w 
move. w 
move. w 
move.w 
move. w 
clr .1 
move.1 
move.w 
trap 
add. 1 
tst .w 
bmi 
jsr 
rts 

readser: move.w 
jsr 
jsr 

move.1 

jsr 

rts 


drbyte,dO 
#1, dl 
#1024,dO 
readweit 
#2, dl 
dl,-(a7) 
wside,-(a7) 
wtrack,-(a7) 
wsector,-(a7) 
wdrive,-(a7) 
-<a7) 

tspacetr, — (a 7) 
#8,-<a7) 

#14 

#20,a7 
dO 

readser 

showsec 


dO,-(a7) 
errhand 
cursmess 
#sefragl,aO 
printf 


* XBIOS call 

* restore stack 

* did an error 

* if so, then 

* else display 

* and return 


occur? 

print message 
sector read 


;* error number on stack 
;* handle error 


;* and return 


221 






Abacus 


Atari ST Disk Drives Inside and Out 


★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A** 

* Show the sector on the screen; the showit subroutine is used, * 

* which displays everything passed to it; see also editsec * 

***★★***★***★★★*****★★★**★*★★★*★★*■*★*★**★*★★*★★★★***★★★★★*★*★★★★★★★**** 


showsec: move.w #0,head2 

move.1 editpt r,t oppt r 

move.w #31,prcount 

move.w #18,lincount 
move.w # 0,maxdown 

move.w #208,maxup 
move.w drbyte,dO 
cmp.w #1024,dO 

bne showse2 

move.w #512,maxdown 

move.w #720,maxup 
move.w #63,prcount 
showse2: jsr showit 
rts 


;* pointer in sector 

;* pointer to start of sector 

;* counter for printing 
;* number of displayed lines 
;* scroll-down flag 
;* scroll-up flag 

;* bytes in sector/ from GAP menu 

;* if 1024, then 

;* set scroll-up and scroll-down 
;* flags accordingly 
;* and print-line counter 


*********************************************************************** 

* Universal display routine, which handles keyboard input, scrolls * 

* up and down and checks for the 'p' key for printer output. A * 

* pointer to the start of the memory area to be displayed is passed * 

* as well as the upper and lower boundaries. * 

*********************************************************************** 


showit: 

jsr 

cursbuf 




jsr 

emptybuf 

• * 
r 

empty keyboard buffer 


move.w 

#0,head2 

• ★ 
t 

pointer in sector 

showit3: 

move. w 

head2,headl 

• ★ 
r 

to pointer for dispbuf rout. 


jsr 

dispbuf 

• k 
/ 

write this buffer 


jsr 

emptybuf 

• ★ 
r 

empty keyboard buffer 


jsr 

cursbuf 



showit4: 

jsr 

key 

• ★ 
t 

read keyboard 


swap 

dO 




cmp .b 

#$19,dO 

• ★ 

test if 'p'-key pressed 


beq 

printit 

• ★ 
r 

if so, output to printer 


cmp.b 

#$48,dO 

• ★ 

! 

test for cursor up 


beq 

upper 

• •k 
r 

if so, handle it 


cmp.b 

#$50,dO 

• * 
r 

test for cursor down 


beq 

lower 

• * 

if so, handle it 


cmp.b 

#$lc,d0 

• * 
r 

test for 'RETURN' key 


beq 

shsecli 




cmp.b 

#$4b,dO 

• ★ 

test for cursor left 


beq 

shsecli 

• * 
r 

if so 


222 






Abacus 


Atari ST Disk Drives Inside and Out 



cmp .b 

#$4d,dO 

• ★ 
r 

test for cursor right 


bne 

showit4 

• ★ 

/ 

if not, then back to loop 


jsr 

curright 

• ★ 

/ 

else cursor right 


bra 

showiten 

. * 
r 

to calling program section 

shsecli: 

jsr 

curleft 

. * 
r 

call cursor left and back 

showiten 

: rt s 


• ★ 
r 

to calling program section 

upper: 

move.w 

head2,d0 

• * 
r 

handle cursor up 


cmp.w 

#0, dO 

• ★ 
t 

if the pointer points to the st 


beq 

uppend 

• ★ 
f 

of the sector, then do nothing 


cmp.w 

maxup,dO 

• ★ 

if it points to the upper limit 


beq 

upper1 

• ★ 
t 

then subtract 208 


sub . w 

#256,head2 

• ★ 
t 

else subtract 256 


sub.l 

#256,topptr 

• ★ 
t 

from pointer in sector. 


bra 

uppend 

• ★ 
t 

and counter and return 

upper1 : 

sub.w 

#208,head2 

• it 
f 

subtract 208 from pointer in 


sub.l 

#208,topptr 

• ★ 
t 

sector 

uppend: 

bra 

showit3 

• ★ 
t 

and back to display 

lower : 

move . w 

head2,dO 

• ★ 
r 

handling cursor down 


cmp.w 

maxup,dO 

• ★ 
r 

as upper, except add to 


beq 

lowend 

• * 
r 

pointer and counter 


cmp.w 

maxdown,dO 




bne 

lowerl 




add.w 

#208,head2 




add.l 

#208,topptr 




bra 

lowend 



lowerl: 

add.w 

#256,head2 




add. 1 

#256,topptr 



lowend: 

bra 

showit3 

• ★ 
r 

keep displaying 


*********************************************************************** 

* Print the contents of the buffer to which topptr points as 16 * 

* 2-digit hex numbers and 16 ASCII characters on the printer. The * 

* number of lines to be printed is passed in prcount. * 

*********************************************************************** 


printit: 

move.w 

#0,device 

• ★ 

conout to printer 


movem.1 

a3-a5/d3-d7,savereg 

• ★ 

/ 

save the registers 


move.1 

#mlsecta,a5 

• ★ 
t 

print current 


move.w 

#45,d7 

. * 
t 

track, sector, and s 

printit0 

: move.b 

(a5)+,dO 




move.w 

dO,-(a7) 




jsr 

conout 

• * 
r 

print 


dbra 

d7,printit0 




move.1 

#mlclusa,a5 

• * 
r 

print cluster number 


move.w 

#13,d7 




223 




Abacus 


Atari ST Disk Drives Inside and Out 


printitl: move.b (a5)+,d0 

move. w dO, -(a7) 

jsr conout 

dbra d7,printitl 

jsr crlinef 

jsr crlinef 

move.l topptr,a4 

move.l a4,a5 

move.w head2,headl 

move.w #15,d3 

move.w d3,d4 

move.w prcount,d5 

printit2: move.w d4,d3 

jsr header 

jsr hexl6 

move.w d4,d3 

move.l a5,a4 

move.w #5,d7 

printit3: move.w #$20,-(a7) 
jsr conout 

dbra d7,printit3 

jsr charl6 

add.l #16,a5 

add.w #16,headl 

jsr crlinef 

dbra d5,printit2 

jsr emptybuf 

movem.l savereg,a3-a5/d3 
move.w #2,device 

bra showit4 


* Carriage return + line feed 

* 2 times 

* pointer in sector 

* store 

* current counter 

* column ctr corresponds to 16 cols 

* store 

* number of lines to print 

* number of lines 

* output the count byte 

* output 16 hex bytes 

* restore counter 

* pointer back to start of sector 

* insert five spaces 

;* output 

;* output 16 ASCII characters 

;* start new line 
;* until all lines 
;* have been printed 
■d7 ;* restore registers 

;* output back to screen 
;* and display the sector 


printerr: rts 

.********************************************************************** 

;* Switch to edit mode in the sector mode; a very flexible editit * 

;* routine is called, which is passed only a pointer to the start of * 

;* the memory area to be edited and two limit variables. * 

.************************************************************★*★**★**** 

r 


jsr 

cursmess 


move. 1 

#edfragl,aO 

;* display edit message 

jsr 

printf 


move.w 

#0,column 


move.w 

#4,line 


jsr 

loccurs 


jsr 

clrest 

;* clear rest of screen 

move.w 

drbyte,dO 



224 



Abacus 


Atari ST Disk Drives Inside and Out 



cmp.w 

#1024,dO 

• ★ 
t 

if 1024 bytes/sector then 


bne 

edseweil 




move . w 

#512 , maxdown 

• ★ 
r 

select higher limit so that 


move.w 

#720,maxup 

• ic 
f 

all 1024 can be edited 


bra 

edsewei2 



edseweil 

: move.w 

#0,maxdown 

. * 
r 

else choose appropriately 


move.w 

#208,maxup 

• * 

! 

smaller limits 

edsewei2 

: move.w 

#18,lincount 

. ★ 
l 

display 19 lines 


move.1 

♦spacetr , editptr 

• ★ 

/ 

buffer address 


jsr 

editit 

• * 
r 

and edit 


jsr 

curleft 

• ★ 
r 

set sector menu 


jsr 

curleft 

. ★ 
t 

back to read 


move . w 

#2 , line 




jsr 

loccurs 




jsr 

delline 

• ★ 
f 

delete line 


jsr 

cursmess 




move . 1 

#sefragl,aO 

• ★ 
r 

display message 


jsr 

printf 




jsr 

cursoff 

• ★ 
r 

disable cursor 


jsr 

showsec 

• ★ 
r 

and display sector again 


jsr 

emptybuf 

• ★ 
r 

empty keyboard buffer 


rts 


• ★ 
r 

and return 


f 

;* This is the flexible edit routine, which can edit an arbitrary * 
;* number of 16-byte lines and which displays these as 16 hex * 

;* numbers and 16 ASCII characters. * 

r 


editit: movem.l a3-a6/d3-d7,-(a7) 
move.l editptr,topptr 
move.w #0,head2 

move.w #0,headl 

jsr dispbuf 

jsr emptybuf 

move.w #7,column 
move.w #4,line 

jsr loccurs 

editsO: jsr curson 

move.l #retwl,-(a7) 
jsr hexin 

jsr cursoff 

tst.w retwl 

bmi otherkey 

move.w line.dO 

subq.w #4,d0 


;* save registers 
;* buffer address 
;* initialize counter for buffer 

;* display first buffer side 
;* empty keyboard buffer 
;* edit starts in column 7 

;* position cursor 

;* turn cursor on 

;* pass address of variable 

;* to hexin, this address 

;* contains the number 

;* entered, if the number was 

;* negative, then other key pressed 

;* current line 

;* start offset of the first line 


225 




Abacus 


Atari ST Disk Drives Inside and Out 


editsl: 


otherkey 


oleft: 


oleftl: 


oright: 


lsl . w 

#4, dO 

. ★ 
f 

times 16 characters/line 

move. w 

column,d2 

• * 
r 

plus column - start offset 

sub .w 

#7,d2 



ext. 1 

d2 

• ★ 

/ 

divided by 3 characters per 

divu 

#3,d2 

. ★ 
t 

byte (1 space + 2 digits) 

add.w 

d2,d0 

• * 

/ 

plus line offset 

move.w 

retwl,dl 

• ★ 
r 

hex digit entered 

move.1 

topptr,a3 

• ★ 

/ 

start address of the buffer 

move.b 

dl,0(a3,d0.w) 

• * 
t 

enter digit in buffer, with 

jsr 

dispzeil 

• * 
r 

offset as pointer, display line 

cmp .w 

#52,column 

• * 
t 

was it the last edit byte 

bit 

editsl 

• ★ 

/ 

in the line? 

move.w 

#4,column 

• ★ 

if so, then back to start of line 

addq.w 

#3,column 

• ★ 
f 

else add 3 char/byte 

jsr 

loccurs 

• ★ 
r 

position cursor 

bra 

editsO 

. * 
f 

and continue editing 

: move.1 

varll,dO 

• ★ 
r 

branch here if invalid 

swap 

dO 

• ★ 

/ 

digit is entered 

cmp .b 

#$4b,dO 

• ★ 

/ 

cursor left? 

beq 

oleft 

• ★ 

! 

yes, handle it 

cmp .b 

#$4d,dO 

• ★ 
r 

cursor right 

beq 

oright 



cmp .b 

#$50,dO 

• ★ 
t 

cursor down 

beq 

odown 



cmp .b 

#$48,dO 

• ★ 
t 

cursor up 

beq 

oup 



cmp .b 

#$52,dO 

• * 
r 

insert key 

beq 

edendl 



cmp .b 

#$72,dO 

• ★ 
f 

enter key 

beq 

edendl 

• * 

/ 

end edit mode 

cmp .b 

#$lc,dO 

• ★ 
r 

Return key ends 

beq 

edendl 

• ★ 
t 

the edit mode 

jsr 

dispzeil 

• ★ 
r 

else display line 

jsr 

loccurs 

• ★ 
r 

position cursor 

bra 

editsO 

• * 
t 

and continue editing 

move.w 

column,dO 

• ★ 
f 

cursor left 

cmp.w 

#7, dO 

• ★ 
r 

cursor already at left edge 

bgt 

oleftl 

• ★ 
/ 

if not, then continue 

move.w 

#55,column 

• ★ 
r 

if so, wrap around 

subq.w 

#3,column 

• ★ 
t 

if not, subtract 3 char/byte 

jsr 

loccurs 

• ★ 
/ 

position cursor 

jsr 

emptybuf 

• ★ 
f 

empty keyboard buffer 

bra 

editsO 

• * 
t 

and continue editing 

move. w 

column,dO 

• ★ 
/ 

the same in green for cursor 

cmp.w 

#52,dO 

• ★ 
r 

right 


226 




Abacus 


Atari ST Disk Drives Inside and Out 



bit 

orightl 


move.w 

#4, column 

orightl: 

addq.w 

#3,column 


jsr 

loccurs 


jsr 

emptybuf 


bra 

editsO 

odown: 

jsr 

cursoff 


move.w 

line,dO 


cmp .w 

#22,dO 


bit 

odown2 


move.w 

head2,dO 


cmp .w 

maxdown,dO 


bne 

odownl 


add .w 

#208,head2 


add. 1 

#208,topptr 


move.w 

column,oldspal 


jsr 

dispbuf 


move.w 

oldspal,column 


move.w 

#5,line 


jsr 

loccurs 


bra 

odownend 

odownl: 

cmp.w 

maxup,dO 


beq 

odownend 


add.w 

#256,head2 


add. 1 

#256,topptr 


move.w 

column,oldspal 


jsr 

dispbuf 


move.w 

oldspal,column 


move. w 

#6,line 


jsr 

loccurs 


bra 

odownend 

odown2: 

addq.w 

#1,line 


jsr 

loccurs 

odownend 

: jsr 

emptybuf 


bra 

editsO 

oup: 

jsr 

cursoff 


move.w 

line,dO 


cmp.w 

#4, dO 


bne 

oup2 


move. w 

head2,dO 


cmp.w 

#0, dO 


beq 

oupend 


cmp.w 

maxup,dO 


beq 

oupl 


sub ,w 

#256,head2 


* cursor down pressed 

* current line 

* less than 22 

* if so, continue 

* else compare counter 

* with limit 

* if not equal, continue 

* if equal, process rest of 

* buffer, adding 

* 208 instead of 256 

* first display buffer 

* cursor in old column 

* offset in buffer 

* position cursor 

* and back 

* if equal to upper limit 

* then do nothing 

* else add 256 to the 

* pointers 

;* and display the buffer 


;* and return 

;* if not in line 22, then 
;* increment current line by one 
;* empty keyboard buffer and 
;* continue editing 

;* same as for cursor down 
;* except for cursor up 
;* current line = line 4 
;* if not, then continue 
;* if so, load counter 
;* at top of edit buffer? 

;* yes, do nothing 
;* no, compare with limit 
;* if equal, subtract only 208 
;* else subtract 256 from the 


227 





Abacus 


Atari ST Disk Drives Inside and Out 



sub. 1 

#256,topptr 

• * 

/ 

pointers, 


move.w 

column,oldspal 

• ★ 
t 

load old column 


jsr 

dispbuf 

• ★ 

display buffer 


move.w 

oldspal,column 

• ★ 

cursor in old column 


move.w 

#19,line 

• ★ 

/ 

offset in line 


jsr 

loccurs 

• ★ 
r 

position cursor 


bra 

oupend 

• * 
r 

and to end 

oupl: 

sub .w 

#208,head2 

. * 

display top of buffer 


sub. 1 

#208,topptr 




move.w 

column,oldspal 




jsr 

dispbuf 




move.w 

oldspal,column 




move.w 

#19,line 




jsr 

loccurs 



oup2: 

subq.w 

#1,line 

• ★ 
r 

if not in top line. 


jsr 

loccurs 

• ★ 
t 

simply decrement line 

oupend: 

jsr 

emptybuf 

• ★ 
t 

empty keyboard buffer 


bra 

editsO 

• ★ 

/ 

and continue editing 

edendl: 

move.w 

#0,column 

• * 
t 

terminate edit, position 


move.w 

#4,line 

• ★ 
r 

cursor in line 4 


jsr 

loccurs 




movem.1 

(a7)+,a3-a6/d3-d7 

• ★ 
r 

restore registers 


rts 


• ★ 
t 

and return 


writsec: 

movem.1 

a3-a6/d3-d7,-(a7) 

» ★ 
t 

write a sector to the disk 


move. w 

#0,column 

. * 

first ask if we should 


move. w 

#2,line 

• ★ 
r 

really write it 


jsr 

loccurs 




move.1 

#wrfragl,aO 




jsr 

printf 




move. 1 

♦mlsecta,a3 

. * 
t 

current track, sector, etc. 


move. w 

#45,d3 

• ★ 
t 

output to screen 

writll: 

move.b 

(a3) +, dO 




move. w 

d0,-(a7) 




jsr 

conout 




dbra 

d3,writll 




move. 1 

#wrfrag2,aO 




jsr 

printf 




jsr 

emptybuf 

• ★ 
r 

empty keyboard, and 


jsr 

wkey 

• -k 
t 

wait for keypress 


cmp .b 

#'y',dO 

• ★ 
t 

if neither 'y' nor 'Y' 


beq 

writit 

• ★ 
r 

was pressed, then don't write 


cmp .b 

#'Y',dO 




bne 

wrendl 

• ★ 

jump to end 


228 






Abacus 


Atari ST Disk Drives Inside and Out 


writit: 


writil: 


wrend2: 


wrendl: 


writerr: 


move. w 

drbyte,dO 

* 

if drbyte = 1024, then use 

cmp .w 

#1024,dO 

★ 

custom write-sector 

BEQ 

SELFSECT 

★ 

routine 

move.w 

#1, dl 

★ 

else write a sector 

move.w 

dl, -(a7) 

* 

number 

move.w 

wside,-(a?) 

* 

side 

move.w 

wtrack,-(a7) 

★ 

track 

move.w 

wsector,-(a7) 

★ 

sector 

move. w 

wdrive,-(a7) 

* 

drive 

clr. 1 

— (a 7) 

★ 

dummy long word 

move.1 

#spacetr,-(a7) 

★ 

buffer address 

move.w 

#9,-(a7) 

★ 

flopwr 

trap 

#14 

★ 

XBIOS call 

add. 1 

#20,a7 



tst .w 

dO 

* 

test for error 

bmi 

writerr 


handle error 

jsr 

delline 



jsr 

emptybuf 



jsr 

cursmess 

* 

display mode 

move.1 

#sefragl,aO 



jsr 

printf 



movem.1 

(a7)+,a3-a6/d3-d7 



rts 


• ★ 

and return 

jsr 

delline 



move.1 

#wrfrag3,aO 

• * 

message = "not written" 

jsr 

printf 



jsr 

emptybuf 



jsr 

wkey 



bra 

wrend2 



move.w 

dO,-(a7) 

• * 

handle error 

jsr 

errhand 



bra 

wrend2 




. ★******★**★*★★**★★***★***★*******★**★★*★*★★*★*★★★*★***★*★■*■**★★★*★■*•★*** 


• ★ 



Here we start with the modular assembly language routines. * 

Routines here are simply the routine name and an RTS. Only the * 
sector menu is operational, meaning that you can only read and * 
and write sectors. Provided this shell program works properly, * 
you can add the complete subroutines from the other listings 
here. The best thing to do is enter the entire block that belongs* 
to a menu option, because most menu options access routines in * 
other menu options. You should pay some attention to the order * 
of the implementation. Recommended: first OPTION, then TRACK, * 


229 





Abacus 


Atari ST Disk Drives Inside and Out 


;* followed by TRACK with SYNCS, FORMAT, and CLUSTER. * 

j*******************************************************************^.^ 

/*********************************************************************** 
!* Subroutines of the menu option OPTION should be implemented first * 

;* because this makes it possible to read the 10th sector, access * 

;* track 82, etc. In addition, some routines are called by other * 

;* program parts. * 

.*********************************************************************** 

/Include OPTIONS.S * See page 256 * 

incmaxtr: rts 

decmaxtr: rts 

incmaxse: rts 

decmaxse: rts 

dodrivin: rts 

showbpb: rts 

initdriv: rts 

rdfat: rts 

.*********************************************************************** 

;* Subroutines of the menu option TRACK of the main menu plus * 

;* a custom write-sector routine * 

,. *********************************************************************** 

************************************************************************ 
;* custom sector-write routine, directly accesses the controller and * 
/* DMA chip. The XBIOS routinefor writing sectors, in contrast to the * 
/* sector-read routine, cannot write sectors of 1024 bytes, so we * 

;* our own routine. It is not possible to write 1024-byte sectors * 

/* with the initial version of the program (sector menu only). * 

************************************************************************ 


/INCLUDE SELFSECT.S 
selfsect: rts 


* See page 262 * 


/* Subroutines of the option TRACK from the main menu * 


/include 

"track 

readltr: 

rts 

incstra: 

rts 

decstra: 

rts 

edittr: 

rts 

showtr: 

rts 


230 


Abacus 


Atari ST Disk Drives Inside and Out 


writltr: rts 

.*★************★************★******★★****★********★*★**************** 
;* Subroutines of the menu option TRACK with SYNCS, the routines * 
;* don't access any other routines, so this option can be * 

;* implemented as desired. * 

.******************************************************************** 

r 

/include "tracksync.s" * See page 269 * 

rdtracks: rts 

shtracks: rts 

readadr: rts 

showadr: rts 


.*********************************************************************** 

r 

;* Subroutines of the menu option CLUSTER of the main menu, the 
;* routines access routines from OPTION, so you must implement OPTION * 

;* first. * 

.*****★★*******★**★★*★*★***★*★****************************************** 

r 


;INCLUDE 
edclust: 
decclust: 
incclust: 
nextclst: 
wrclust: 
rdclust: 
stclust: 


"cluster.s 
rts 
rts 
rts 
rts 
rts 
rts 
rts 


II 


* See page 278 * 


.*********************************************************************** 

I 

;* Format subroutines from the main menu * 

;* These routines access subroutines from the menu option * 

;* TRACK with SYNCS, so TRACK with SYNCS must be implemented first * 

.*********************************************************************** 

r 


/include "format.s" 


formatl: 

rts 

xformat: 

rts 

incgapl: 

rts 

incgap2: 

rts 

incgap3: 

rts 

incgap4: 

rts 

incgap5: 

rts 

decgapl: 

rts 

decgap2: 

rts 

decgap3: 

rts 

decgap4: 

rts 


* See page 293 * 


231 



Abacus 


Atari ST Disk Drives Inside and Out 


decgap5: rts 
incbyte: rts 
decbyte: rts 


* * 

* Here are some often-needed subroutines * 

* * 

* draws a horizontal line from 0,10 to 639,10 (color) * 


hline: 

move. 1 

lineavar,aO 

• ★ 
r 

pointer to line-A variables 


move. w 

#0,38(aO) 

• * 

/ 

XI 


move. w 

#10,40(aO) 

• ★ 
t 

Y1 20 for mono 


move. w 

#639,42(aO) 




move. w 

#1,24(aO) 

• ie 
r 

color 


move. w 

#0,36(aO) 

• ★ 
r 

write mode 


move. 1 

#pattern,46(aO) 

• * 
r 

pattern + number of pattern 


move. w 

#0,50(aO) 

• ★ 
f 

horizontal line 


dc. w 

$a004 




rts 





;* Write a string to the screen * 


printf: 


move.1 

aO,- (a 

move.w 

#9,-(a 

trap 

#1 

addq. 1 

#6,a7 

rts 



;* write the string pointed to 
;* by address register AO 
;* to the screen 
;* string must be terminated 
;* with zero 


.********************************************************************** 
!* Initialize the line-A variables, and store the address of the * 

;* variable block in "lineavar". * 

;********************************************************************** 


inlinea: 


dc. w 

$a000 

;* initializes the line-A variables 

move.1 

aO,lineavar 

;* store address 

move.w 

#0,32(aO) 


move.w 

#$ffff,34(aO) 

;* line pattern 

move.w 

#0,36(aO) 

;* Writing mode = replace 

move. w 

#1,24(aO) 

;* character color 

rts 




232 









Abacus 


Atari ST Disk Drives Inside and Out 


.******************************************************************** 
r 

;* Initialize line-A * 

.******************************************************************** 

r 

startl: jsr inlinea ;* Initialize line-A 

rts 


.********************************************************************* 

r 

;* Writes a word passed on the stack to the screen as a 2-digit 

;* hexadecimal number, or to the device determined by device 

.********************************************************************* 

/ 


hexpr: 

move.w 

4(a?) , dl 

;* get argument from stack 


and.w 

#$00ff,dl 

;* mask out high word 


move.w 

dl,varwl 

;* store byte 


lsr .w 

#4, dl 

;* shift lower nibble out 


ext .w 

dl 

;* expand to word 


and.w 

#$00ff,dl 

;* mask out high byte 


cmp.w 

#9, dl 

;* greate than nine, then 


bgt 

ischarl 

;* print a char from 'A'-'F' 


jsr 

hexdig 

;* else a digit '0'—'9 1 


bra 

secdigl 


ischarl: 

jsr 

hexchar 


secdigl: 

move.w 

varwl,dl 

;* convert lower nibble of low 1 


and.w 

#$000f,dl 

;* mask out upper 


cmp.w 

#9, dl 

;* greater than nine, see above 


bgt 

ischar2 



jsr 

hexdig 



bra 

hexpren 

; * to end 

ischar2: 

jsr 

hexchar 


hexpren: 

move.1 

(a7)+,aO 

;* return address still on the 


add. 1 

#2,a7 



jmp 

(aO) 

;* back to caller, like rts 

hexdig: 

add.w 

#48,dl 

;* add ASCII value of 'O' 


MOVE. W 

Dl, -(A7) 



move.w 

device,-(a7) 

;* and print 


move.w 

#3,-(a7) 

;* conout 


trap 

#13 

;* BIOS-TRAP 


addq.1 

#6,a7 



rts 



hexchar: 

sub .w 

#10,dl 

;* subtract ten and add ASCII 


add.w 

#65,dl 

;* value of 'A' 


move.w 

dl,-(a7) 



move.w 

device,-(a7) 

;* and print 


233 


Abacus 


Atari ST Disk Drives Inside and Out 


move.w #3,-(a7) 
trap #13 

addq.l #6,a7 
rts 

;* Output a 2-byte integer in decimal * 


dezpr: 

move.w 

#0,dflag 

• ★ 

print a 2-byte integer in decimal 


move. w 

4(a7),d3 

• ★ 

/ 

suppress leading zeros 


ext. 1 

d3 

• ★ 
r 

and output as spaces 


divs 

#10000,d3 




beq 

dezprl 

• ★ 

/ 



move.w 

#-l,dflag 

• ★ 

/ 

flag for requested output, don't 

dezpr1: 

jsr 

deznum 

• ★ 
r 

print 


swap 

d3 

• ★ 

/ 

rem of 1st division by 1000 


ext. 1 

d3 

• ★ 
r 

divide 


divs 

#1000,d3 

• ★ 
t 

and print as 1000's place 


beq 

dezpr3 



dezpr2: 

move.w 

#-l,dflag 

• ★ 
r 

not zero, set flag 

dezpr3: 

jsr 

deznum 




swap 

d3 




ext .1 

d3 

• ★ 

! 

divide rem by 100 


divs 

#100,d3 




beq 

dezpr4 




move.w 

#-l,dflag 



dezpr#: 

jsr 

deznum 

• ★ 
f 

and print 

dezpr5: 

swap 

d3 




ext. 1 

d3 




divs 

#10,d3 

• * 

! 

divide rem by 10 and 


beq 

dezpr7 




move.w 

#-l,dflag 



dezpr7: 

jsr 

deznum 

• \k 
t 

print as ten's place of number 


swap 

d3 

• * 
t 

print rem of last division 


move.w 

#-l,dflag 

• ★ 
t 

in any event because zero 


jsr 

deznum 

• ★ 
t 

should be displayed if 


move . 1 

(a7) +, aO 

. * 

! 

the result is zero. 


addq.1 

#2,a7 

. * 
t 

get return address in A0, restore 


jmp 

(aO) 

• ★ 

stack, and return to caller 

deznum: 

tst .w 

dflag 

• ★ 
r 

print a digit from 'O'-'9' 


bne 

deznuml 

• ★ 
r 

but only if dflag is not null 


move . b 

#' 1 , dO 




move . w 

dO, - (a7) 




bra 

deznum2 




234 




Abacus Atari ST Disk Drives Inside and Out 


deznuml: add.b 

#' 0 ', d3 

;* add ASCII value of 'O' 

move.w 

d3,-(a7) 


deznum2: jsr 

conout 

;* print 

rts 



dezlpr: move.w 

#0, dflag 

;* prints a 4-byte integer, which 

move.X 

4 <a7),d3 

;* is passed on the stack as a long 

word. 



move.1 

d3,d4 

;* in decimal 

divs 

#10000,d3 

;* leading zeros 

ext .1 

d3 

;* will be printed as 

divs 

#10,d3 

;* spaces 

move.w 

d3,d5 

;* first divide by 100000 

tst .w 

d3 

;* if zero, then no 100000's place 

beq 

dezlprl 


move. w 

#-l,dflag 


dezlprl: jsr 

deznum 

;* else print the 100000's place 

move. w 

d5,d3 

;* multiply result of division 

muls 

#10,d3 

;* by 100000, handle result 

muls 

#10000,d3 

;* as for dezpr 

sub.l 

d3,d4 


move.1 

d4,d3 


divs 

#10000,d3 


beq 

dezlpr3 


dezlpr2: move.w 

#-l,dflag 


dezlpr3: jsr 

deznum 


swap 

d3 


ext .1 

d3 


divs 

#1000,d3 


beq 

dezlpr4 


move.w 

#-l,dflag 


dezlpr4: jsr 

deznum 


swap 

d3 


ext. 1 

d3 


divs 

#100,d3 


beq 

dezlpr5 


move.w 

#-l,dflag 


dezlpr5: jsr 

deznum 


swap 

d3 


ext .1 

d3 


divs 

#10,d3 


beq 

dezlpr6 


move.w 

#-l,dflag 


dezlpr6: jsr 

deznum 


swap 

d3 


move. w 

#-l,dflag 


jsr 

deznum 



235 


Abacus 


Atari ST Disk Drives Inside and Out 


move.l (a7)+,a0 

addq.l #4,a7 
jmp (aO) 

;* Display the menu * 


dispweil 


dispmen3 


move . w 

#0,column 

• * 
r 

cursor to top line 

move.w 

#0,line 



jsr 

loccurs 

• ★ 
r 

position 

move.1 

menuadr,a6 

• ★ 
t 

here is a pointer to the 

move . 1 

revnum,d6 

• k 
t 

addresses of the mnu strings 

subq.1 

#1, d6 

• * 
r 

revnum contains the number 

beq 

dispweil 

• ★ 
r 

of the menu option displayed 

subq.1 

# 1, d6 

• k 
r 

in reverse 

move.1 

(a 6)+,aO 

• k 

f 

get the individual addresses. 

jsr 

printf 

• ★ 

! 

and print with printf, until all 

dbra 

d6,dispmenl 

• * 
r 

strings up to the reverse are 



• ★ 
t 

printed 

jsr 

revon 

• * 
r 

then display the reverse 

move . 1 

(a6) +, aO 

• ★ 
r 

string 

jsr 

printf 

• * 

/ 

turn reverse off again 

jsr 

revout 



move . 1 

ganz,d7 

• ★ 
r 

total number of menu options 

sub.l 

revnum,d7 

• -k 
r 

minus the reverse number 

beq 

dispmen3 

• ★ 

/ 

if zero, then it was the last 

subq.1 

#1 , d7 

• ★ 
r 

else display the remaining 

move . 1 

(a6)+,aO 

• * 
t 

options in normal 

jsr 

printf 



dbra 

d7,dispmen2 

• ★ 
t 

until all have been printed 

jsr 

hline 

• ★ 
r 

then draw a horizontal line 

jsr 

delrest 

• ★ 
r 

and return 


********************************************************************** 

* Write the contents of a memory range, whose start address is * 

* passed in topptr, as 16 2-digit hex numbers, as well as 16 ASCII * 

* characters, on the screen. * 

********************************************************************** 


dispbuf: movem.l a3-a5/d3-d7,savereg 
move.l topptr,a4 
move.l a4, a5 
move.w head2,headl 
move.w #15,d3 
move.w d3,d4 


;* store registers 

;* start address of memory range 

;* store 

;* counter for offset in block 
;* column counter = 16 columns 
;* store 


236 



Abacus 


Atari ST Disk Drives Inside and Out 


dispbl: 


move. w 

lincount,d5 

move. w 

#4, line 

move.w 

#4, curzeil 

move.w 

#0, column 

jsr 

loccurs 

move. w 

#0, column 

move.w 

curzeil,line 

move.w 

d4,d3 

jsr 

loccurs 

jsr 

header 

jsr 

hexl 6 

move.w 

d4,d3 

move.1 

a5, a4 

move.w 

#59,column 

move.w 

curzeil,line 

jsr 

loccurs 

jsr 

charl6 

add. 1 

#16,a5 

add.w 

#1,curzeil 

add.w 

#16,headl 

dbra 

d5,dispbl 

jsr 

emptybuf 

movem.1 

rts 

savereg,a3-a5/d3-d? 


;* number of lines passed 
;* in lincount 

;* cursor to line 4 column 0 

;* position 

;* position cursor 
;* to current line 
;* column counter 

; * print counter in block 
;* print 16 hex numbers 
; * column counter 
;* topptr 

;* ASCII characters in column 59 

;* print 16 ASCII characters 
;* add 16 to pointer in memory 
;* continue with next line 
;* add 16 to counter 
;* until all lines displayed 
;* empty keyboard buffer 
;* and restore registers 


;* write a header before each line 


header: move.w 

headl,d6 

;* counter 

lsr. w 

#8,d6 

;* divide by 256 (high byte) 

move.w 

d6,- (al) 

;* print as hex number 

jsr 

hexpr 


move.w 

headl,-(a7) 

;* print low byte 

jsr 

hexpr 


move.b 

#' : ',d6 

;* print colon 

move.w 

d6,—(a7) 


jsr 

conout 


rts 

• ★*★★★**★★*★★★★***★***★ 

;* write 16 hex 

numbers 

★ 

. *********************** 

hexl6: move.w 

#$20,-(a?) 

;* print two spaces 

jsr 

conout 



237 



Abacus 


Atari ST Disk Drives Inside and Out 


move.w 

#$20,-(a7) 


jsr 

conout 


hexl61: move.b 

(a4) +, d7 

;* print the contents of 16 memory 

move.w 

d7,-(a7) 

;* locations as hex numbers 

jsr 

hexpr 

;* a space after each one 

move.w 

#$20,-(a 7) 


jsr 

conout 

;* pass counter in d3 

dbra 

d3,hexl61 


rts 



.*********************************************************************** 

;* write 16 ASCII characters 

to the screen * 

.*********************************************************************** 

char16: move.b 

#':',d7 

;* first a colon and 

move.w 

d7,-(a7) 


jsr 

conout 


move.w 

#$20,-(a7) 

;* two spaces; then 

jsr 

conout 


charl61: move.b 

(a4)+,d7 

;* print 16 ASCII characters 

cmp.b 

#$20,d7 

;* print everything less than $20 

bgt 

charl62 

;* as a period 

move.b 

#'.',d7 


charl62: ext.w 

d7 

;* else mask out high byte 

and.w 

#$00ff,d7 


move.w 

d7,-(a7) 


jsr 

conout 

;* and print 

dbra 

d3,charl61 

;* 16 times, pass in d3 

rts 



.*********************************************************************** 

;* write an entire line on the 

screen * 

; *********************************************************************** 

dispzeil: move.w 

column,oldspal 

;* print a line in 16/16 format 

move.w 

#0,column 


jsr 

loccurs 

;* position cursor 

move. w 

oldspal,column 


move.w 

#15,d3 

;* 16 columns 

move. w 

d3,d4 


move. 1 

topptr,a4 

;* pointer to start of memory 

clr. 1 

dO 

;* range, calculate with help 

move.w 

line,dO 

;* of current line, the position 

subq.w 

#4, dO 

;* relative to the start of the 



;* range 

lsl. w 

#4, dO 

;* times 16 

move. w 

dO, dl 

;* store 


238 




Abacus 


Atari ST Disk Drives Inside and Out 


add.w 

head2,dO 

• ★ 
t 

move. w 

dO,headl 

. * 
t 

ext. 1 

dl 


add. 1 

dl, a4 

• ★ 
t 

move.1 

a4, a5 

• ★ 
t 

jsr 

header 

• ★ 

/ 

jsr 

hexl 6 

• ★ 
r 

move.w 

column,oldspal 


move.w 

#59,column 


jsr 

loccurs 


move.w 

d4,d3 


move.1 

a5, a4 

• ★ 
r 

jsr 

charl6 


move.w 

oldspal,column 

• ★ 
9 

jsr 

rts 

loccurs 

• * 
t 


add counter offset 
place in current counter 

add to pointer in memory range 
equal to pointer 
to the line being edited 
print 16 numbers 


and 16 ASCII characters 

restore old column and 
position cursor 


.********************************************************************** 

r 

;* Routines for terminal emulation 

*********************************************************************** 

9 

revon: move.l #reversl,aO ;* Turn reverse print on 

jsr printf 

rts 


revout: move.l #revers2,a0 

jsr printf 

rts 

delrest: move.l #clrest2,a0 
jsr printf 

rts 

delline: move.l #dellinel,aO 
jsr printf 

rts 

clear: move.l #clearl,aO 

jsr printf 

rts 


;* turn reverse off 


;* delete rest of line 


;* delete entire line 


;* clear entire screen 
;* and position cursor in 
;* upper left corner 


home: move.l #homel,aO ;* position cursor in upper 

jsr printf ;* left corner 

rts 


239 


Abacus 


Atari ST Disk Drives Inside and Out 


crlinef: 

move. w 

jsr 

move. w 

jsr 

rts 

#$lc,-(a7) 

conout 

#$0a,-(a7) 
conout 

• ★ 
r 

• * 

/ 

output carriage return with 
linefeed on output device 

clrest: 

move.l 

jsr 

rts 

#clrestl,aO 
printf 

• ★ 
r 

clear rest of screen 

curson: 

move.1 

jsr 

rts 

#curonl,aO 
printf 

• ★ 
r 

turn cursor on 

cursoff: 

move.1 
jsr 

rts 

#curoutl,aO 
printf 

• ★ 
r 

turn cursor off 

cursmess 

: move.w 

move.w 

jsr 

rts 

#30,column 
#2,line 
loccurs 

• ★ 
r 

• ★ 

/ 

position cursor 
for printing messages 


cursbuf: move.w #0,column 
move.w #4,line 
jsr loccurs 

rts 


;* position cursor 

!* for printing sector buffer 


;* Cursor positioning * 


loccurs: 


curstab: 


move.1 

tloccursl,aO 

• ★ 
r 

position the cursor to the 

addq.1 

o 

CM 

=#= 

• ★ 
t 

coordinates passed in line 

move.w 

line,dO 

• ★ 
r 

and column, (0-79),(0-24) 

add.w 

#32,dO 

• ★ 
r 

add internal offset 

move.b 

dO,(aO)+ 

. ★ 
r 

store 

move.w 

column,dO 



add.w 

#32,dO 

• * 
r 

add internal offset 

move.b 

dO,(aO)+ 

• ★ 
r 

and store 

move.1 

#loccursl, aO 

• ★ 
r 

print modified 

jsr 

printf 

• ★ 
r 

position command 

rts 




move.w 

tabl,column 

• ★ 
r 

positions the cursor in 

jsr 

loccurs 

• ★ 
r 

column tabl of the current line 

rts 





240 


Abacus 


Atari ST Disk Drives Inside and Out 


.*********************************************************************** 

f 

;* Read keyboard, does not wait and returns scan code as well as 

;* ASCII in DO. If no key was pressed, D0=0. 

.****★★**★************************************************************** 

r 


key: move.w 

#2,-(a7) 

;* read keyboard 

move.w 

#1, -(a7) 

;* output the ASCII code of 

trap 

#13 

;* the pressed key in the low byte 

addq.1 

#4,a7 

;* of the lower word of DO 

tst .w 

dO 

;* return scan code in low byte 

bpl 

endtast2 

;* of upper word of DO. 

move.w 

#2,-(a7) 

;* if key was pressed 

move.w 

#2,-(a7) 

;* get key from buffer and 

trap 

#13 

;* return 

addq.1 

#4,a7 


rts 



endtast2: move.1 

#0, dO 

;* else return zero 

rts 



emptybuf: move.w 

#$b,-(a7) 

;* empty keyboard buffer 

trap 

#1 


addq.1 

#2,a7 


tst. w 

dO 


beq 

emptyl 


move.w 

#7,-(a7) 


trap 

#1 


addq.1 

#2,a7 

;* repeat until no more 

bra 

emptybuf 

;* characters in buffer 

emptyl: rts 



conout: move.w 

4(a7),dO 

;* display a character on the 

move. w 

dO, -(a7) 

;* specified device 

move. w 

device,-(a7) 

;* see ATARI ST INTERNALS 

move. w 

#3,-(a7) 


trap 

#13 


addq.1 

#6,a7 


move.1 

(a7)+, aO 

;* get return address 

addq.1 

#2,a7 


jmp 

(aO) 


wkey: move.w 

#1,-<a7) 

;* keyboard input 

trap 

#1 

;* wait for input and 

addq.1 

#2,a7 

;* display flashing cursor 

rts 




241 



Abacus 


Atari ST Disk Drives Inside and Out 


j******************************************************************,^^ 

;* Read a 1-byte hex number and store it in the address passed * 

;* on the stack. * 


hexin: jsr 

move.1 

cmp.b 

bgt 

cmp.b 

bit 

sub .b 

add.b 

bra 

hexin1: cmp.b 

bit 
cmp.b 
bgt 
sub.b 
hexin2: lsl.w 

move.w 
jsr 

move.1 

cmp.b 

bgt 

cmp.b 

bit 

sub.b 

add.b 

bra 

hexin3: cmp.b 

bit 
cmp.b 
bgt 
sub.b 

hexin4: move.w 

or .w 
ext ,w 
and.w 
move.w 
hexin5: move.l 

move.w 
move.1 
addq.1 
jmp 


wkey 
dO,varll 
#'f',d0 
hexeierr 

# 1 a 1 , dO 
hexinl 

# ' a 1 , dO 
#10,dO 
hexin2 
#' 0 1 , dO 
hexeierr 
#' 9',d0 
bstestl 
# 1 0 1 ,dO 
#4, dO 
dO, varwl 
wkey 

dO,varll 
#'f \d0 
hexeierr 
#'a',dO 
hexin3 
#'a',dO 
#10,dO 
hexin4 

# 1 0',dO 
hexeierr 
#'9',d0 
bstest2 

# 1 0',dO 
varwl, dl 
dl, dO 
dO 

#$00ff,dO 
dO,varw2 
4(a7),aO 
dO,(aO) 
(a7)+,aO 
#4,a7 
(aO) 


;* assign hex number (2 digits) 

;* to the variable passed 
;* on the stack 

;* if an illegal key was pressed 
;* return -1 

;* test if between 'a' and 'f* 

;* if so, subtract 'a', and add 10 

;* if not, then test if between 
;* zero and nine 

;* if not, then test if ('A'-'F') 
;* else subtract 'O' 

;* times 16 = high nibble 
;* store 

;* get next nibble 
;* store 

;* same test as for first nibble 


;* test for uppercase 


;* return without error 


;* back to caller 


242 


Abacus 


Atari ST Disk Drives Inside and Out 


hexeierr: 

: move.w 

#-l,dO 





bra 

hexin5 

• * 
f 

return with error code 

bstestl: 

cmp.b 

#' F 1 , dO 

• ★ 
r 

test if between 'A' 

and 


bgt 

hexeierr 

• ★ 
r 

if not, then return 

with 


cmp.b 

#'A 1 ,dO 

• ★ 
r 

error code 



bit 

hexeierr 

• * 
t 

else subtract ASCII 

'A' 


sub.b 

# 1 A',dO 

• * 
r 

add ten 



add .b 

#10,dO 





bra 

hexin2 

• ★ 
t 

get next nibble 


bstest2: 

cmp.b 

#'F 1 ,dO 

• ★ 
r 

same as bstestl for 

the 


bgt 

hexeierr 

. * 
t 

second nibble 



cmp.b 

#'A',dO 





bit 

hexeierr 





sub.b 

#'A 1 ,dO 





add.b 

#10,dO 





bra 

hexin# 





* Variables for the basic program * 


*★★★★★★***★*★**★*★★★**★*★*★★★******★*★★*★★*********★*★*****•*■★**■*•*•*★ 

* Menu data for the main menu, addresses of the menu strings, * 

* addresses of the subroutines (haincjmp) * 

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★it** 


data 


dc.l 

gotrack 

dc. 1 

gosync 

dc. 1 

gosector 

dc.l 

goclust 

dc. 1 

goformat 

dc.l 

goinit 

dc. 1 

mainend2 

dc. 1 

mlhaula 

dc. 1 

mlhaulal 

dc. 1 

mlhaulb 

dc. 1 

mlhaulbl 

dc.l 

mlhaulc 

dc. 1 

mlhauldl 

dc.l 

mlhaule 


243 






Abacus 


Atari ST Disk Drives Inside and Out 


mlhaula: 

dc .b 

1 

TRACK 

',0 

mlhaulal 

: dc .b 

1 

TRACK/SYNCS ', 0 

mlhaulb: 

dc .b 

1 

SECTOR 

',0 

mlhaulbl 

: dc .b 

1 

CLUSTER 

',0 

mlhaulc: 

dc.b 

1 

FORMAT 

',0 

mlhauld: 

dc .b 

1 

FATS 

',0 

mlhauldl 

: dc.b 

1 

OPTIONS 

',0 

mlhaule: 

dc.b 

' 

END ' 

,0 

hafragl: 

dc. b 

27 

,'p A LITTLE DISK UTILITY (C) U. Braun 1986 


dc.b 

27 

, 'q' ,0 


hafrag2: 

dc. b 

27 

, 'P 

ATARI ST DISK DRIVES INSIDE AND OUT 


dc.b 

27 

, 'q',0 


hafrag3: 

dc.b 

27 

. 'P 

Select menu items with cursor keys 


dc. b 

27 

, 'q',0 



★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★it****** 

* Addresses of sector menu strings (mensect) and the sector menu * 

* routines * 

align 


sedecjmp 


mensect: 


dc. 1 

incdrive 

dc. 1 

incside 

dc. 1 

inctrack 

dc.l 

incsect 

dc. 1 

readsec 

dc. 1 

writsec 

dc.l 

editsec 

dc. 1 

gomain 

dc. 1 

decdrive 

dc. 1 

decside 

dc. 1 

dectrack 

dc. 1 

decsect 

dc. 1 

readsec 

dc. 1 

writsec 

dc. 1 

editsec 

dc. 1 

gomain 

dc. 1 

mlsecta 

dc.l 

mlsectb 

dc. 1 

mlsectc 

dc. 1 

mlsectd 

dc. 1 

mlsecte 

dc. 1 

mlsectf 

dc. 1 

mlsectg 

dc. 1 

mlsecth 


244 





Abacus 


Atari ST Disk Drives Inside and Out 


mlsecta: 

dc. b 

' drive: 

1 



mdrive: 

dc. b 

'O',' ', 0 




mlsectb: 

dc. b 

' side: ' 




mside: 

dc. b 

■O’,' ', 0 




mlsectc: 

dc. b 

' track: 

i 



mtrack: 

dc .b 

■O', 'O', ' 

',0 



mlsectd: 

dc. b 

' sector: 

' 



msector: 

dc .b 

'O', ' 1 ' , ’ 

',0 



mlsecte: 

dc .b 

' READ 

', 0 



mlsect f: 

dc .b 

' WRITE 

' , 0 



mlsectg: 

dc. b 

' EDIT 

' , 0 



mlsecth: 

dc .b 

' BACK 

',0 



wrfragl: 

dc.b 

27, 'p',' 

Write this 

sector to: ', 

27,'q',0 

wrfrag2: 

dc. b 

27,'p <yes,no> ? ' 

,27,'q',0 


wrfrag3: 

dc.b 

27, 'p Not 

written. 

<press key> ' 

,27,'q',0 

sefragl: 

dc.b 

27, 'p SECTOR MODE 

',27,'q',0 


edfragl: 

dc. b 

27, 'p EDIT MODE: 

< return > := 

END ' ,27, 'q',0 


r 

;* Addresses for the TRACK menu * 

• **★★★★****★****★★***★**★*★*★★*★★★★★★**★★★★★*★★★★★★★★★★★**★★*★*•****'★ 

/ 

trincjmp: dc.l incdrive 

dc.l incside 

dc.l inctrack 

dc.l incstra 

dc.l readltr 

dc.l writltr 

dc.l edittr 

dc.l gomain 

trdecjmp: dc.l decdrive 

dc.l decside 

dc.l dectrack 

dc.l decstra 

dc.l readltr 

dc.l writltr 

dc.l edittr 

dc.l gomain 

mentrack: dc.l mlsecta 

dc.l mlsectb 

dc.l mlsectc 

dc.l mltracal 

dc.l mltracka 

dc.l mltrackb 


245 





Abacus 


Atari ST Disk Drives Inside and Out 


dc.l mltrackc 

dc.l mltrackd 


mltracal: 

: dc.b 

' Sec/Trk : ' 



setrack: 

dc.b 

O 

kD 

O 



mltracka: 

dc.b 

’ READ •,0 



mltrackb: 

dc.b 

’ WRITE ',0 



mltrackc: 

dc.b 

' EDIT Tr. ',0 



mltrackd: 

dc.b 

' BACK 1 ,0 



trfragl: 

dc. b 

27,'p TRACK MODE 

; ',27 

,'q',0 

trfrag2: 

dc.b 

21,'p TRACK WITH 

SYNCS 

MODE •,27, 'q',0 

trfrag3: 

dc.b 

27,'p Sector: 1 , 

0 


trfrag4: 

dc.b 

' ',27,'q',0 



trfrag5: 

dc.b 

27,'p Write this 

track 

to ' ,27, 'q',0 

trfrag6: 

dc.b 

27,'p < yes/no > 

',27, ' 

q',0 


************************************************************************ 

t 

;* Addresses for the TRACK with SYNCS menu * 

************************************************************************ 

/ 

align 

syincjmp: dc.l incdrive 

dc.l incside 

dc.l inctrack 

dc.l rdtracks 

dc.l readadr 

dc.l gomain 

sydecjmp: dc.l decdrive 

dc.l decside 

dc.l dectrack 

dc.l rdtracks 

dc.l readadr 

dc.l gomain 

mensync: dc.l mlsecta 

dc.l mlsectb 

dc.l mlsectc 

dc.l mlsynca 

dc.l mlsyncb 

dc.l mltrackd 

mlsynca: dc.b ' READ WITH SYNCS ',0 

mlsyncb: dc.b ' ADDR. FIELD ',0 


246 



Abacus 


Atari ST Disk Drives Inside and Out 


•★★★**★**★**★★********★**★*★★★***★*★★★★★★*★★*★****★★**★★*★**** 

;* Cluster * 


clincjmp: 

dc.l 

inedrive 


dc. 1 

incclust 


dc. 1 

rdclust 


dc. 1 

nextclst 


dc. 1 

wrclust 


dc. 1 

edclust 


dc. 1 

stclust 


dc. 1 

gomain 

cldecjmp: 

: dc.l 

deedrive 


dc. 1 

decclust 


dc. 1 

rdclust 


dc. 1 

nextclst 


dc. 1 

wrclust 


dc. 1 

edclust 


dc. 1 

stclust 


dc. 1 

gomain 

menclust: 

: dc.l 

mlsecta 


dc. 1 

mlclusa 


dc.l 

mlsecte 


dc. 1 

mlclusb 


dc. 1 

mlsectf 


dc.l 

mlclusd 


dc. 1 

mlclusc 


dc. 1 

mlsecth 

mlclusa: 

dc.b 

' CLUST: ' 

mlclusal 

: dc.b 

O 

o 

o 

o 

o 

mlclusb: 

dc.b 

' NEXT ',0 

mlclusc: 

dc.b 

' STARTofFILE ',0 

mlclusd: 

dc. b 

' EDIT ’,0 

clfragl: 

dc.b 

27,'p CLUSTER MODE ',27,'q',0 

elfrag2: 

dc.b 

27,'p When leaving CLUSTER MODE, last read 1 


dc.b 

'Cluster is updated in SECTOR Menu ',27,'q',0 

elfrag4: 

dc. b 

27,'p This was the last cluster ',27,'q',0 

selfragl 

: dc.b 

27, 'p Filename: File attribute: ' 


dc.b 

' Start cluster: Number of bytes: ',21, 

selfrag2 

: dc.b 

27,'p Put start cluster in menu with <RETURN> 


dc.b 

1 read with <up>, <down>. ',27,'q',0 

elfrag5: 

dc .b 

27,'p Write this cluster to: ',27,'q',0 


247 




Abacus 


Atari ST Disk Drives Inside and Out 


trecsiz: dc.b ' Bytes per sector: ',0 

tclsiz: dc.b ' Sectors per cluster: ',0 

tclsizb: dc.b ' Bytes per cluster: ',0 

trdlen: dc.b 1 Sectors per directory: ',0 

tfsiz: dc.b ' Sector per FAT: ',0 

tfatrec: dc.b 1 Sector number of second FAT:',0 

tdatrec: dc.b ' Sector of first data cluster:',0 

tnumcl: dc.b 1 Number of clusters: ',0 

tnumsides: dc.b 1 Number of sides: ',0 

tdirl: dc.b 27,'p First directory sector on Side: 0 Track: 1 

dc.b ' Sector: 3 ',27,'q',0 

tdir2: dc.b 27,'p First directory sector on Side: 1 Track: 0 



dc.b 

1 Sector: 3 ',21, 

'q 

tfolder: 

dc.b 

' Subdirectory 

,0 

treadwr: 

dc.b 

1 Read/Write 

,o 

treadon: 

dc.b 

1 Read only 

,0 

thidden: 

dc. b 

' HIDDEN File 

,0 

tdelet: 

dc.b 

' Deleted 

,0 

tdisname 

dc.b 

' Diskette name 

,0 


;* Format menu 
align 


foincjmp: 

dc. 1 

incdrive 


dc. 1 

incside 


dc.l 

inctrack 


dc. 1 

incstra 


dc. 1 

formatl 


dc. 1 

xformat 


dc. 1 

gogaps 


dc. 1 

gomain 

fodecjmp 

: dc.l 

decdrive 


dc. 1 

decside 


dc. 1 

dectrack 


dc. 1 

decstra 


dc. 1 

formatl 


dc.l 

xformat 


dc. 1 

gogaps 


dc. 1 

gomain 

formmen: 

dc.l 

mlsecta 


dc.l 

mlsectb 


dc. 1 

mlsectc 


dc. 1 

mltracal 


248 





Abacus 


Atari ST Disk Drives Inside and Out 



dc. 1 

mlformd 


dc. 1 

mlforme 


dc. 1 

mlformf 


dc. 1 

mlformg 

mlformd: 

dc. b 

' FORMAT ' , 0 

mlforme: 

dc. b 

' XFORMAT ',0 

mlformf: 

dc.b 

' GAPS ',0 

mlformg: 

dc .b 

' BACK ',0 

fofragl: 

dc.b 

27,'p Format track mode ',27,'q',0 

fofrag2: 

dc. b 

27, 'p Track : ',0 

fofrag3: 

dc. b 

' format ? <yes/no> ',27,'q l ,0 

fofrag4: 

dc.b 

27, 'p Not formatted <key> ',27,"q',0 

fofrag5: 

dc. b 

' on side : 1 ,0 

fofrag6: 

dc.b 

' of drive: 1 ,0 

xffragl: 

dc. b 

27,'p Really format with new GAPs ' 


dc. b 

'between the sectors? <yes/no> ',27,'q',0 

xffrag2: 

dc. b 

27,'p Wait a second, then press key ',27, , q',0 

M1F0RM1: 

DC. b 

1 Format track ',0 

• ★**★★*★*★★**********★*****★★*★***★******★***★★★**■*•★★★★★★*★★★**★ 

;* Init menu 


• ★★★★★★★★★★*★**★*★★★★★★*★**★■*•***★*★*★★***★**★★***★***★*★★★*★**** 

inincjmp 

: dc. 1 

incdrive 


dc. 1 

incmaxtr 


dc. 1 

incmaxse 


dc. 1 

dodrivin 


dc. 1 

showbpb 


dc. 1 

gomain 

indecjmp 

: dc. 1 

decdrive 


dc. 1 

decmaxtr 


dc. 1 

decmaxse 


dc. 1 

dodrivin 


dc. 1 

showbpb 


dc.l 

gomain 

meninit: 

dc. 1 

mlsecta 


dc.l 

mldrina 


dc. 1 

mldrinb 


dc. 1 

mldrinc 


dc. 1 

mldrincl 


dc. 1 

mldrind 


249 




Abacus 


Atari ST Disk Drives Inside and Out 


mldrina: 

dc. b 

' MAXTRACK: ' 

maxltr: 

dc.b 

' 7 ' , ' 9', 1 ',0 

mldrinb: 

dc. b 

' MAXSECTOR: '• 

maxlse: 

dc. b 

•O’, ' 9•, ■ ',0 

mldrinc: 

dc. b 

' INIT DRIVE ',0 

mldrincl 

dc.b 

• SHOW BPB ',0 

mldrind: 

dc.b 

' BACK ',0 

drifragl 

dc.b 

27, 'p INIT DRIVE MENU ',27, 'q',0 

drifrag2 

dc.b 

27,'p Bios Parameter Block of active drive ' 


dc. b 

' < press key > ',27,'q',0 

catfral: 

dc. b 

27,'p Directory starts at Side: 0 Track: 1 Sector 


dc.b 

27, 1 q 1 ,0 

catfra2: 

1 

dc.b 

27,'p Directory starts at Side: 1 Track: 0 Sector 


dc. b 

27,'q',0 

device: 

dc .w 

2 

drive: 

dc .w 

0 

side: 

dc.w 

0 

track: 

dc .w 

0 

sektor: 

dc.w 

0 

seek : 

dc.w 

3 

savesr: 

dc. w 

0 

flstatus 

dc.w 

0 

• ★*★★★★★*★*★★■*■**★***★★★★****★★★★★★★*★★* 

;* Gap menu 

★ 

.***************************************************************** 

gpinc jmp 

dc.l 

incgapl 


dc. 1 

incgap2 


dc. 1 

incgap3 


dc. 1 

incgap4 


dc. 1 

incgap5 


dc. 1 

incbyte 


dc. 1 

goformat 

gpdecjmp 

: dc.l 

decgapl 


dc. 1 

decgap2 


dc. 1 

decgap3 


dc. 1 

decgap4 


dc. 1 

decgap5 


dc.l 

decbyte 


dc. 1 

goformat 


250 





Abacus 


Atari ST Disk Drives Inside and Out 


mengap: 

dc. 1 

mlgapa 



dc.l 

mlgapb 



dc.l 

mlgapc 



dc.l 

mlgapd 



dc. 1 

mlgape 



dc. 1 

mlgapf 



dc. 1 

mlgapg 


mlgapa: 

dc. b 

' GAP1 

• 1 

mgapl: 

dc .b 

'60 ' , 

0 

mlgapb: 

dc .b 

' GAP 2 

• 1 

mgap2: 

dc. b 

■12 ■ , 

0 

mlgapc: 

dc. b 

' GAP 3 

• 1 

mgap3: 

dc .b 

■22 ' , 

0 

mlgapd: 

dc .b 

* GAP 4 

• 1 

mgap4: 

dc. b 

■40 ' , 

0 

ml gape: 

dc.b 

' GAP 5 

• 1 

mgap5: 

dc.b 

•664 ' 

,0 

mlgapf: 

dc.b 

' Bytes/ec: ' 

mdrisect 

: dc.b 

'0512 

', o 

mlgapg: 

dc.b 

' BACK 

', 0 

drfragl: 

dc.b 

27, 'p 

Drive format mode , ,27, , q',0 

gpfragl: 

dc.b 

27, 'p 

Change gaps between sectors , ,27,'q',0 

slfragl: 

dc.b 

27, 'p 

Please wait a second, then press a key 

',21, 'q' 

,0 



slfrag3: 

dc. b 

27, -p 

SECTOR MODE ',27,'q',0 

dr byte: 

dc. w 

512 


gapl: 

dc .w 

60 


gap2 : 

dc .w 

12 


gap3: 

dc .w 

22 


gap 4: 

dc. w 

40 


gap5: 

dc. w 

664 


sadfragl 

: dc.b 

27, 'p 

Track: Side: Sector: Bytes: Checksum(hex) 1 


dc.b 

27,'q' 

,0 

.*********************************************************************** 

;* Here 

are the escape 

sequences for the terminal emulation, such as * 

;* reverse on 

and off. 

cursor positioning, etc. * 

; *********************************************************************** 

clrestl: 

dc. b 

27,'J' 

, o 

clrest2: 

dc. b 

27,'K' 

,0 

reversl: 

dc.b 

27,'p' 

,0 

revers2: 

dc .b 

27,'q' 

,0 


251 





Abacus 


Atari ST Disk Drives Inside and Out 


loccursl 

dc.b 

27, 

Y 

,33,33,0 

homel: 

dc.b 

27, 

■H' 

,0 

clearl: 

dc.b 

27, 

■E' 

,0 

curupl: 

dc.b 

27, 

'A' 

,0 

curdownl 

dc.b 

27, 

'B' 

,0 

inslinel 

dc.b 

27, 

■L' 

,0 

dellinel 

dc.b 

27, 

•1' 

,0 

overoutl 

dc.b 

27, 

' w 

,0 

curoutl: 

dc. b 

27, 

■ f 

,0 

curonl: 

dc. b 

27, 

'e 

,0 

spaces: 

dc.b 

1 


',0 

hilcurs: 

dc. b 

27, 

' J 

,0 


• ★★★★★*★★★*★*★★*★*■**■*★******★★★★★*****★***★****★***★★*★*★★*'*■**★★** 

;* Addresses of error strings * 

• **★**★**★★★*★★★★★★***★★*****★*'*•★★★*★*★**•**★*★★★**★****★★★**★*** * 


align 
errtab: 

dc. 1 

errorl 


dc. 1 

error2 


dc. 1 

error3 


dc. 1 

error4 


dc. 1 

error5 


dc. 1 

error6 


dc. 1 

error7 


dc. 1 

error8 


dc.l 

error9 


dc. 1 

errorlO 


dc. 1 

errorll 


dc. 1 

errorl2 


dc. 1 

errorl3 


dc. 1 

errorl4 


dc.l 

errorl5 


dc. 1 

errorl6 


dc. 1 

errorl7 


dc.l 

error18 


dc. 1 

errorl9 


dc. 1 

error20 


dc.l 

error21 


dc.l 

error22 


dc. 1 

error23 


dc. 1 

error24 


dc. 1 

error25 


dc. 1 

error2 6 


dc. 1 

error27 


dc. 1 

error28 


dc. 1 

error29 


252 





Abacus 


Atari ST Disk Drives Inside and Out 


;* Here are the actual error strings * 


error1: 

dc. b 

27,'p',' NO BOOTSECTOR ',27,'q',0 

error2: 

dc. b 

27,'p Directory sector defective <key> 

error3: 

dc. b 

' error3',0 

error4 : 

dc. b 

' error4',0 

error5: 

dc.b 

' error5 ',0 

error6: 

dc .b 

' error6 ',0 

error7: 

dc. b 

27,'p',' Insert disk / track not present 

error8: 

dc. b 

' error8 ',0 

error9: 

dc. b 

27,'p',' Sector does not exist!',27,'q', 

errorlO 

dc. b 

' errorlO',0 

errorll 

dc.b 

' errorll',0 

errorl2 

dc. b 

' errorl2',0 

errorl3 

dc. b 

' errorl3 ',0 

errorl4 

dc. b 

27,'p Please remove write protect. ',2 

error15 

dc. b 

' errorl5 ',0 

errorl6 

dc. b 

' errorl6 ',0 

errorl7 

dc.b 

' errorl7',0 

errorl8 

dc. b 

' errorl8 ',0 

error19 

dc. b 

' errorl9 ',0 

error2 0 

dc.b 

27,'p No more clusters ',27,'q',0 

error21 

dc.b 

' error21 ',0 

error22 

dc.b 

' error22 ',0 

error23 

dc.b 

' error23 ',0 

error24 

dc.b 

' error24 ',0 

error25 

dc.b 

' error25 ',0 

error26 

dc. b 

' error26 ',0 

error27 

dc.b 

' error27 ',0 

error28 

dc. b 

' error28 ',0 

error29 

dc. b 

' error29 ',0 

pattern 

dc. w 

bss 

$ffff 

menuadr 

ds.l 

1 

ganz: 

ds . 1 

1 

revnum: 

ds . 1 

1 

jmptable: ds.l 

1 

wtrack: 

ds . w 

1 

wsector 

ds . w 

1 

wside: 

ds . w 

1 

wdrive: 

ds . w 

1 


253 



Abacus 


Atari ST Disk Drives Inside and Out 


wclust: 

ds . w 

1 

maxtrack: 

: ds .w 

1 

maxsect: 

ds . w 

1 

maxdriv: 

ds . w 

1 

maxside: 

ds. w 

1 

maxclust 

: ds .w 

1 

topptr: 

ds . 1 

1 

oldtop: 

ds . 1 

1 

botptr: 

ds . 1 

1 

column: 

ds. w 

1 

line: 

ds . w 

1 

headl: 

ds. w 

1 

head2: 

ds . w 

1 

curzeil: 

ds . w 

1 

curspal: 

ds . w 

1 

oldzeil: 

ds. w 

1 

oldspal: 

ds . w 

1 

lincount 

: ds .w 

1 

prcount: 

ds . w 

1 

retwl: 

ds . w 

1 

incvar: 

ds . 1 

1 

decvar: 

ds . 1 

1 

usstack: 

ds . 1 

1 

sustack: 

ds . 1 

1 

dmastat: 

ds. w 

1 

currdma: 

ds .b 

1 

highdma: 

ds .b 

1 

middma: 

ds .b 

1 

lowdma: 

ds .b 

1 

maxhead: 

ds . w 

1 

savebpb: 

ds . 1 

1 

recsiz: 

ds . w 

1 

clsiz: 

ds. w 

1 

clsizb: 

ds . w 

1 

rdlen : 

ds . w 

1 

f siz: 

ds. w 

1 

fatrec: 

ds . w 

1 


254 




Abacus 


Atari ST Disk Drives Inside and Out 


datrec: 

ds . w 

1 

numcl: 

ds . w 

1 

bflags: 

ds . w 

1 

oldsec: 

ds. w 

1 

dflag: 

ds . w 

1 

eflag: 

ds . w 

1 

edflag: 

ds . w 

1 

numsides 

: ds .w 

1 

tabl: 

ds . w 

1 

oldclst: 

ds. w 

1 

newclst: 

ds . w 

1 

clstnum: 

ds. w 

1 

logsect: 

ds . w 

1 

asector: 

ds. w 

1 

topdma: 

ds. 1 

1 

editptr: 

ds. 1 

1 

savereg: 

ds.l 

16 

maxdown: 

ds . w 

1 

maxup: 

ds . w 

1 

lineavar 

: ds.l 

1 

varll: 

ds. 1 

1 

varwl: 

ds . w 

1 

varw2: 

ds . w 

1 

varw3: 

ds . w 

1 

dirptr: 

ds.l 

1 

dirbuf: 

ds . w 

4000 

fatbuf: 

ds . w 

4000 

formbuf: 

ds. w 

6000 

spacetr: 

ds. w 

6000 


end 

Next are the complete subroutines for the individual menu options, which 
end in rts in the above listing of edit . s. 


255 



Abacus 


Atari ST Disk Drives Inside and Out 


You should stick to the suggested order of implementation because some 
menu options access subroutines from other menus. If you complete the 
program in the manner suggested, you will not run into problems of this 
type. 

First is the subroutine for the Options menu, which allows you to set the 
maximum track and sector and view the BIOS parameter block. 


; 

;* OPTION.S subroutines should be implemented first because they allow* 
;* access to the 10th sector, 82nd track, etc, and some routines are * 
;* called by other parts of the program. * 

•★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★it*** 

t 


• ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A - ****** 
r 

;* initialize current drive (from the menu) and store the variables * 
;* of the BIOS parameter block. * 

r 


initdriv: move.w wdrive,d0 

move.w wdrive,-(a7) 
move.w #7,-(a7) 

trap #13 

addq.l #4,a7 

tst.l dO 

bne doinitl 

move.w dO,-(a7) 

jsr errhand 

bra doiniten 

doinitl: move.l d0,a0 

move.w (a0)+,recsiz 

move.w (a0)+,clsiz 

move.w (a0)+,clsizb 

move.w (a0)+,rdlen 

move.w (a0)+,fsiz 

move.w (aO)+,fatrec 

move.w (a0)+,datrec 

move.w (a0)+,numcl 

move.w (aO)+,bflags 

move.w (aO)+,numsides 

move.w (aO)+,numsides 

doiniten: rts 


* current drive 

* on the stack 

* Getbpb function 

* BIOS trap 

* restore stack 

* error occurred? 

* if so than pass it 

* and return 

* else dO = base address of the BPB 

* bytes per sector 

* sectors/cluster 

* bytes/cluster 

* sectors/directory 

* sectors/FAT 

* sec. # of second FAT 

* sec. # of first data cluster 

* number of data clusters 

* flags 

* still dummy 

* number of sides 

* and return 


.*********************************************************************** 

;* Read the FAT sectors from the disk into the FAT buffer * 

.****★★★*★**★*★★★★*★★★★★★★★★★★*★*****★**★★********★★★***********★★★★★*★* 

r 


256 





Abacus 


Atari ST Disk Drives Inside and Out 


rdfat: 

move.w 

wdrive,-(a7) 

• ★ 
t 


move.w 

fatrec,-(a7) 

• ★ 
r 


move.w 

fsiz,- (a7) 

• ★ 
r 


move.1 

#fatbuf,-(a7) 

• ★ 
/ 


move.w 

#2,-(a7) 

• ★ 
t 


move.w 

#4,-<a7) 

• ★ 
r 


trap 

#13 

• ★ 
f 


add. 1 

#14,a7 

• ★ 
r 


tst . w 

dO 

• ★ 
r 


bmi 

rdfater 

• ★ 
r 

rdfatend 

: rt s 


• ★ 
t 

rdfater: 

move.w 

dO, -(a7) 

• ★ 
r 


jsr 

errhand 

• ★ 
/ 


bra 

rdfatend 

• ★ 
/ 


★ ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★it*' 

* Read the directory sectors from 
★★***★★★*★★★★*★★★★★★*★****★★****★★• 


current drive 

sector # of the second FAT 
# of sectors per FAT 
buffer address on the stack 
read 

Rwabs function 
BIOS trap 
restore stack 
error occurred? 
if so, then handle 
else return 

error number on the stack 

handle 

and return 

the disk into a buffer * 


rddir: 

move.w 

wdrive,-(a7) 

* 

current drive 


move.w 

fsiz,dO 

★ 

number of FAT sectors 


lsl. w 

#1, dO 

•k 

times two (FAT's) plus one 


addq.w 

#1, dO 

★ 

equals logical sector number of the 


move.w 

dO,-(a 7) 

* 

first directory sector 


move.w 

rdlen,-(a7) 

★ 

number of directory sectors 


move.1 

#dirbuf,-(a7) 

* 

address of the buffer 


move.w 

#2,-<a7) 

★ 

read 


move.w 

#4,-(a7) 

★ 

Rwabs function 


trap 

#13 

* 

BIOS 


add. 1 

#14,a7 




tst ,w 

dO 

* 

error? 


bmi 

rddirer 

★ 

yes 

rddirend 

rts 


* 

if not, then return immediately 

rddirer: 

move.w 

dO,-(a7) 

★ 

error number 


jsr 

errhand 




bra 

rddirend 




* Increments the maximum track number that can be set in the Init * 

* drive menu. This also becomes the maximum track number for all * 

* other menues. * 

*★*★**★★*★★**★***★*★★★******★******★****★******★★***★***★★**■*•★**★**★*★* 


incmaxtr: move.w 
cmp .w 


maxtrack,dO 
#99,dO 


;* 99 is the maximum 


257 






Abacus 


Atari ST Disk Drives Inside and Out 


incmal: 
incma2: 


decmaxtr 


decmal: 
decma2: 


incmaxse 


incmasl: 
incmas2: 


bit 

incmal 

;* else same procedure as for 

move .w 

#0, dO 

;* previous menu changes 

bra 

incma2 


addq.w 

#1, dO 


move.w 

dO,maxtrack 


ext. 1 

dO 


divu 

#10,dO 


add.b 

#■0',d0 


move.b 

dO,maxltr 

;* also change in menu text 

swap 

dO 


add.b 

S#8 

O 

a 

o 


move.b 

dO, maxltr+1 


jsr 

dispmen 

;* display menu 

rts 


;* and return 

move.w 

maxtrack,dO 

;* decrements the maximum 

cmp.w 

#0, dO 

;* track number 

ble 

decmal 


subq.w 

#1, dO 


bra 

decma2 


move.w 

#99,dO 


move.w 

dO, maxtrack 


ext. 1 

dO 


divu 

#10,dO 


add.b 

#'0',dO 


move.b 

dO,maxltr 

;* change in menu string 

swap 

dO 


add.b 

#'0',dO 


move.b 

dO,maxltr+1 


jsr 

dispmen 

;* display menu 

rts 


;* and return 

: move.w 

maxsect,dO 

;* same thing with maximum 

cmp.w 

#99,dO 

;* sector number 

bit 

incmasl 


move.w 

#0, dO 


bra 

incmas2 


addq.w 

=*= 

I—* 

a 

o 


move.w 

dO,maxsect 


ext .1 

dO 


divu 

#10,dO 


add.b 

=#= 

O 

a 

o 


move.b 

dO,maxlse 

;* put in menu text 

swap 

dO 



258 




Abacus 


Atari ST Disk Drives Inside and Out 


add .b 

#' 0',dO 



move. b 

dO,maxlse+1 



jsr 

dispmen 

;* display menu 


rts 


;* and return 


decmaxse: move.w 

maxsect,dO 

;* decrement maximum 


cmp.w 

#0, dO 

;* sector number 


ble 

decmasl 



subq.w 

#1, dO 



bra 

decmas2 



decmasl: move.w 

#99,dO 



decmas2: move.w 

dO,maxsect 



ext .1 

dO 



divu 

#10,dO 



add .b 

#' 0',dO 



move.b 

dO, maxlse 

;* change in menu text 


swap 

dO 



add .b 

#' 0 ', dO 



move.b 

dO,maxlse+1 



jsr 

dispmen 

;* display menu 


rts 


;* and return 


•★****★★*★**★***■************★★*★****★*★******★★★★****★★★★★** ★ 

;* This is the actual drive 

init routine, which initializes the 

* 

;* current drive 

(in wdrive) 

and reads the Bios Parameter Block as 

* 

;* well as reading the FAT 

und directory sectors into the given 

★ 

;* buffer. 



★ 

.*********************************************************************** 

dodrivin: jsr 

initdriv 

;* initialize drive 


jsr 

rdfat 

;* read FAT sectors 


jsr 

rddir 

;* read directory sectors 


jsr 

showbpb 

;* display BIOS parameter block 


jsr 

curleft 



dodriven: rts 


;* and return 


.*★★**★*★*★**★*★★★*★*★**★**★***★**★★***★*★*★*★***★***★★**★******** 

;* Display the BIOS parameter 

block 

★ 

•★***★**★★★**★★*★******★*★**★★★★★********★*******★ 

showbpb: move.w 

#4,line 

;* cursor in line 4, column 10 


move.w 

#10,column 



jsr 

loccurs 

;* position 


move. 1 

#drifrag2,a0 ;* output message 


jsr 

printf 



move. w 

#42,tabl 

;* tab on screen for 



259 




Abacus 


Atari ST Disk Drives Inside and Out 


move.w 

#6,line 

• ★ 

/ 

outputting numbers 

move.w 

#12,column 



jsr 

loccurs 



move.1 

ftrecsiz,aO 

• ★ 
r 

bytes per cluster 

jsr 

printf 



jsr 

curstab 

• ★ 
t 

write text 

move.w 

recsiz,-(a7) 

• * 

/ 

write bytes/cluster as decimal 



• ★ 
r 

number 

jsr 

dezpr 



addq.w 

#1,line 

• ★ 
f 

move down one line 

move.w 

#12,column 



jsr 

loccurs 



move.1 

#tclsiz,aO 

• ★ 
r 

sectors per cluster 

jsr 

printf 



jsr 

curstab 



move. w 

clsiz,-(a7) 



jsr 

dezpr 



addq.w 

#1,line 



move.w 

#12, column 



jsr 

loccurs 



move. 1 

#tclsizb,aO 

• ★ 

/ 

bytes per cluster 

jsr 

printf 



jsr 

curstab 



move.w 

clsizb,-(a7) 



jsr 

dezpr 



addq.w 

#1,line 



move.w 

#12,column 



jsr 

loccurs 



move. 1 

ttrdlen,aO 

• ★ 
t 

sectors per directory 

jsr 

printf 



jsr 

curstab 



move. w 

rdlen,-(a7) 



jsr 

dezpr 



addq. w 

#1,line 



move. w 

#12,column 



jsr 

loccurs 



move. 1 

#tfsiz,aO 

• ★ 
r 

sectors per FAT 

jsr 

printf 



jsr 

curstab 



move. w 

fsiz,- (a7) 



jsr 

dezpr 



addq.w 

#1,line 



move. w 

#12,column 



jsr 

loccurs 



move. 1 

#tfatrec,aO 

• ★ 
f 

sector number of the 2nd FAT 

jsr 

printf 



jsr 

curstab 




260 


Abacus 


Atari ST Disk Drives Inside and Out 


move.w 

jsr 

addq.w 
move.w 
jsr 

move.1 

jsr 

jsr 

move.w 
jsr 

addq.w 
move.w 
jsr 

move.1 

jsr 

jsr 

move.w 

jsr 

addq.w 
move. w 
jsr 

move. 1 

jsr 

jsr 

move.w 

jsr 

addq.w 
move. w 
jsr 

move. 1 
move. w 


cmp.w 

bne 

move. 1 

showbpbl: jsr 
jsr 
jsr 
jsr 
jsr 
jsr 

move.1 

jsr 

rts 


end 


fatrec,-(a7) ;* 

dezpr 

#1,line 

#12,column 

loccurs 

#tdatrec,aO ;* sector number of the first data 

printf ;* cluster 

curstab 

datrec,-(a7) 

dezpr 

#1,line 

#12,column 

loccurs 

#tnumcl,aO ;* number of data clusters 

printf 

curstab 

numcl,-(a7) 

dezpr 

#1,line 

#12,column 

loccurs 

#tnumsides,aO ;* number of disk sides 

printf 

curstab 

numsides,-(a7) 

dezpr 

#2,line 

#10,column 

loccurs 

#tdirl,a0 ;* location of first directory 

numsides,dO ;* sector, differentiated fpr 

#2,d0 ;* single and double-sided disks 

showbpbl 

#tdir2,aO 

printf 

emptybuf ;* empty keyboard buffer 

wkey ; * wait for key 

cursmess 

delline 

cursmess 

#drifragl,aO ;* display message 

print f 

;* and return 


261 


Abacus 


Atari ST Disk Drives Inside and Out 


Here are the subroutines for the Track menu: 

.**«******************************************************************* 
;* TRACK menu subroutines plus custom sector—write routine * 

; *************************************************** ([ * tn * tl4t * lill)Ht]U1 

;*********************************************************************** 


;* Custom sector-write routine, accesses controller and DMA chip * 
/* directly. The XBIOS write-sector routine does not work for * 
;* 1024-byte sectors, so this routine is called. The rdstrack menu * 
;* must be implemented before this function can be inserted because * 
;* some routines from this menu are called (super, seldrive, etc.). * 
;* It is not possible to write 1024-byte sectors with the basic * 
;* version of the program (with sector menu only). * 




jsr 

super 

• ★ 
f 

enable supervisor mode 

st 

flock 

• ★ 
r 

disable floppy interrupt 

jsr 

seldrive 

• -k 
f 

select drive and side 

jsr 

flreset 

• ★ 
r 

reset the controller 

jsr 

searcht 

• ★ 
t 

seek track in wtrack 

jsr 

selwrite 

• ★ 
r 

write sector 

s f 

flock 

• ★ 
r 

enable floppy interrupt 

jsr 

emptybuf 

• * 
t 

empty keyboard buffer 

jsr 

cursmess 

• ★ 

/ 

position cursor 

jsr 

delline 

. ★ 

/ 

delete line 

jsr 

flreset 

• ★ 

/ 

controller reset 

jsr 

user 

• ★ 

/ 

enter user mode 

move.1 

#slfragl,aO 

• ★ 
r 

output message 

jsr 

printf 



jsr 

wkey 

• ★ 
t 

wait for keypress 

jsr 

super 

• * 
r 

enter supervisor mode 

jsr 

deselect 

• ★ 
r 

deselect floppy 

jsr 

user 

• ★ 
r 

enter user mode 

jsr 

cursmess 

• * 

/ 

position cursor 

jsr 

delline 

• ★ 
r 

delete line 

jsr 

cursmess 

• * 
r 

position again 

move. 1 

#slfrag3,aO 

• ★ 
r 

output message 

jsr 

printf 



movem.1 

(a7)+,a3-a6/d3-d7 

• * 
r 

restore registers 

rts 


• ★ 
r 

and return 


;* Here the sector is written to the disk * 


262 


Abacus 


Atari ST Disk Drives Inside and Out 


selwrite: jsr setspace 

move.w #$190,dmamode 


move.w 

#$90,dmamode 

move. w 

#$190,dmamode 

move. w 

#4,d6 

jsr 

wrcontr 

move. w 

#$184,dmamode 

move.w 

wsector,d6 

jsr 

wrcontr 

move.w 

#$180,dmamode 

move.w 

#$a0,d6 

jsr 

wrcontr 

move.1 

#$50000,d7 

: btst 

#5,mfp 

beq 

selwrend 

subq.1 

#1, d7 

bne 

selwritl 

move.w 

#-9,-<a7) 

jsr 

errhand 

jsr 

cursmess 

jsr 

delline 

rts 



;* set address of the buffer 
;* switch to write 
;* by "toggling" the read/write 
;* line 

;* write 4 to sector count 
;* register 

;* select FDC sector register 
;* pass current sector to FDC 

;* select controller 
;* sector-write command to 
;* controller 
;* pass 

;* timeout counter 

;* interrupt input of FDC to MFP 

;* if 1 then done 

;* decrement timeout counter, if 

;* not timed-out, keep waiting 

;* else error number 9 on the stack 

;* pass to error handler 

;* output line 

;* delete 


selwrend: jsr 

move. w 
btst 
bne 
rts 

selwerrl: move.w 
jsr 
jsr 
jsr 
rts 


rdstatus 
flstatus,dO 
#6, dO 
selwerrl 


#-8,-(a7) 
errhand 
cursmess 
delline 


;* branch here if no error 

;* write protect 
;* yes 

;* if not, then return 
;* error message # 8 (write protect) 
;* output and clear 
;* output line 


.*********************************************************************** 
r 

;* TRACK subroutines 

.*********************************************************************** 

t 

.*********************************************************************** 

t 

;* This routine reads an entire track or the number of sectors passed * 
;* in asector. Standard sectors of 512 bytes are assumed, so any 
;* deviations must be taken into account by modifying the variable 
;* asector. 

.*********************************************************************** 

r 


263 



Abacus 


Atari ST Disk Drives Inside and Out 


readltr: 

move. w 

#512,dO 

• ★ 
t 

standard sector size 


mulu 

asector,dO 

• ★ 
t 

number of sectors per track 


move. w 

dO,maxhead 

• ★ 

! 

max. number of bytes as counter 


move. w 

asector,-(a7) 

• ★ 

/ 

number of sectors/track from menu 


move.w 

wside,-(a7) 

• ★ 
f 

current side 


move.w 

wtrack,- (a7) 

• ★ 

/ 

current track 


move.w 

#1, -(a7) 

• ★ 
t 

at sector 1 


move.w 

wdrive,-(a7) 

• * 
r 

current drive 


clr .1 

-<a7) 

• ★ 
t 

dummy long word 


move.1 

#spacetr,-(a7) 

• ★ 
r 

buffer address 


move.w 

#8,-(a7) 

• ★ 

call XBios function 8 


trap 

#14 

• ★ 

/ 

clean up stack and 


add. 1 

#20,a7 

• * 
t 

check for errors 


tst .w 

dO 




bmi 

readtler 

• ★ 

if error then output 


jsr 

showtr 

• ★ 
r 

else display track 

readtl2: 

rts 


• ★ 
r 

and return 

readtler 

: move.w 

dO,-(a7) 

• ★ 
r 

pass error number on stack to the 


jsr 

errhand 

• ★ 
t 

error handler, then 


jsr 

emptybuf 

• ★ 
r 

empty keyboard buffer 


jsr 

wkey 

• * 
r 

and wait for keypress 


jsr 

cursmess 

• ★ 
r 

output message 


move.1 

ttrfragl,aO 




jsr 

printf 




jsr 

delrest 




bra 

readtl2 

• ★ 
t 

and return 


.*********************************************************************** 
;* Increases number of sectors per track in menu when cursor up is * 

;* pressed * 

;*********************************************************************** 


incstra: 

move . w 

asector,dO 

• * 
r 

number of sectors per track 


cmp . w 

maxsect,dO 

• ★ 

/ 

compare with max number of sectors 


bit 

incstl 

• ★ 

/ 

if greater or equal, then set 


move. w 

#0, dO 

• ★ 
r 

# sectors/track to zero 


bra 

incst2 

• ★ 
r 

and return 

incstl: 

addq. w 

#1, dO 

• ★ 
r 

else add one to sectors/track 

incst2 : 

move . w 

dO,asector 




ext . 1 

dO 

• ★ 
f 

make change in menu text 


divu 

#10,dO 

. * 
r 

split into ASCII bytes by 


add.b 

O 

V 

o 

=«= 

• * 
r 

dividing by 10 


move . b 

dO,setrack 

• ★ 
r 

and enter in menu 


swap 

dO 

. * 

/ 

do low byte 


add . b 

o 

TJ 

O 

• ★ 
r 

convert into ASCII 


move . b 

dO,setrack+1 

• ★ 
t 

and put in menu 


264 


Abacus 


Atari ST Disk Drives Inside and Out 



jsr 

dispmen 

;* display menu 


rts 


;* and return 

•★★★★★*★★★★★★★***★**** 

;* decrement sectors per track in 

menu * 

•*★★★*** 

**************************************************************** 

decstra: 

move.w 

asector, dO 

;* sectors/track 


cmp.w 

#0, dO 



ble 

decstl 

;* if greater than zero, then 


subq.w 

#1, dO 

;* subtract one, else 


bra 

decst2 


decstl: 

move.w 

maxsect,dO 

;* set maximum number 

decst2: 

move.w 

dO,asector 



ext. 1 

dO 



divu 

#10,dO 



add.b 

#■0',dO 



move.b 

dO,setrack 

;* enter in menu 


swap 

dO 



add.b 

4t= 

O 

a 

o 



move.b 

dO,setrack+1 



jsr 

dispmen 

;* display menu and return 


rts 




;* Supplies variables in general 

edit routine with values (maxdown, * 

;* maxup, etc.) 

and then calls the edit routine * 

• ★**★*★★**★★**★***★★******** 

edittr: 

move.w 

#0,maxdown 

;* only 512 bytes will be edited 


move.w 

#208,maxup 



move.w 

#18,lincount 

;* and 19 lines will be displayed 


move.1 

topptr,dO 

;* pointer in the track buffer 


sub. 1 

#spacetr, dO 

;* minus start address of the buffer 


divu 

#512,dO 

;* divide by number of bytes per 


swap 

dO 

;* sector, if remainder. 


tst .w 

dO 

;* then it was not the start of 


beq 

edittrl 

;* of a sector and we must 


sub.l 

#256,topptr 

;* subtract 256 

edittrl 

: move. 1 

topptr,editptr 

;* pass this pointer 


move.w 

#0, head2 

;* in track buffer to editit 


move. w 

#20, column 

;* output message in column 20 of 


move.w 

#2,line 

;* line 2 


jsr 

loccurs 



move. 1 

#edfragl,aO 



jsr 

printf 



jsr 

editit 

;* and call edit 


265 



Abacus 


Atari ST Disk Drives Inside and Out 


jsr 

cursmess 

;* message line 

jsr 

delline 

;* delete 

jsr 

cursmess 


move. 1 

#trfragl,aO 

• ★ 

/ 

jsr 

printf 


jsr 

curleft 

;* set menu back to read 

jsr 

curleft 


jsr 

cursbuf 

• ★ 

jsr 

clrest 

;* clear rest of screen 

rts 


;* and return 


*********************************************************************** 
* Allows the tracks read into the buffer to be viewed * 

*********************************************************************** 


showtr: 

move .w 

#0,head2 

• ★ 
f 

byte counter 


move. 1 

#spacetr,topptr 

• ★ 
r 

start of buffer 


move .w 

#0,edflag 

• * 
r 

flag 


move. w 

#15,lincount 

• * 
t 

16 lines will be displayed 


move. w 

#2,line 

• ★ 
t 

the current sector in column 


move. w 

#59,column 

• * 
t 

of the second line 


jsr 

loccurs 




move. 1 

#trfrag3,aO 

• ★ 
t 

display 


jsr 

printf 




clr .w 

dO 




move. w 

#1, dO 




move. w 

dO, -(a7) 




jsr 

dezpr 

• ★ 
f 

Print sector 


move. 1 

#trfrag4,aO 




jsr 

printf 



showtl: 

move.w 

#4,line 

• * 
r 

position cursor 


move. w 

#0,column 




jsr 

loccurs 




jsr 

clrest 

• ★ 
r 

clear rest of screen 


jsr 

emptybuf 



showt2: 

jsr 

dispbuf 

• ★ 
t 

display first page and 

showt3: 

jsr 

key 

• ★ 
t 

read keyboard 


swap 

dO 




cmp .b 

#$48,dO 

• ★ 
r 

cursor up ? 


beq 

showtup 




cmp .b 

#$50,dO 

• * 

cursor down ? 


beq 

showtdo 




cmp .b 

#$lc,dO 

• ★ 
t 

Return ? 


beq 

showtenl 




cmp.b 

#$4b,dO 

• ★ 
r 

cursor left ? 


beq 

showtli 




266 



Abacus 


Atari ST Disk Drives Inside and Out 


cmp.b 

#$4d,dO 

;* cursor right ? 

beq 

showtre 


bra 

showt3 

;* none of the above, keep readir 

showtre: jsr 

curright 

;* cursor on right menu option 

bra 

showtenl 

;* and return 

showtli: jsr 

curleft 

;* display left menu option in 
;* reverse 

bra 

showtenl 

;* and return 

showtup: move.w 

head2,dO 

;* compare byte counter 

cmp.w 

#0, dO 

;* with zero 

beq 

showtuen 

;* if not equal to zero. 

sub .w 

#256,head2 

;* then subtract 256, correspond: 

sub. 1 

#256,topptr 

;* half a sector 

showtuen: move.w 

head2,dO 

;* byte counter 

lsr .w 

#8, dO 

;* divide by 512 

lsr.w 

#1, dO 


add. w 

#1, dO 

;* plus one equals sector number 

move.w 

dO,varw3 


move.w 

#59,column 


move.w 

#2,line 


jsr 

loccurs 


move.1 

#trfrag3,aO 

;* output current sector number 

jsr 

printf 

;* in line 2 

move. w 

varw3,-(a7) 


jsr 

dezpr 


move. 1 

#trfrag4,aO 


jsr 

printf 


jsr 

delrest 

;* clear rest of line 

showtuel: bra 

showt2 

;* an back to loop 

showtdo: move.w 

head2,dO 

;* cursor down handling 

move.w 

maxhead,dl 


sub .w 

#256,dl 


cmp.w 

dl, dO 


beq 

shwtrden 


add.w 

#256,head2 

;* add 256 buffer pointer and 

add.l 

#256,topptr 

;* byte counter 

shwtrden: move.w 

head2,dO 


lsr .w 

#8, dO 


lsr .w 

#1, dO 

;* divide byte counter by 512 

add.w 

#1, dO 

;* and add one 

move.w 

dO,varw3 

;* yields current sector number 

move.w 

#59,column 


move.w 

#2,line 


jsr 

loccurs 



267 


Abacus 


Atari ST Disk Drives Inside and Out 


move. 1 

#trfrag3,aO 

jsr 

printf 

move.w 

varw3,-(a?) 

jsr 

dezpr 

move.1 

#trfrag4,aO 

jsr 

printf 

jsr 

delrest 

shwtrdl: bra 

showt2 

showtenl: jsr 

rts 

emptybuf 

writltr: move.l 

a4,-(a7) 

move.w 

#2,line 

jsr 

loccurs 

jsr 

delline 

move.1 

#trfrag5,aO 

jsr 

printf 

move.w 

#33,d2 

move.1 

#mlsecta,a4 

writIt1: move.b 

(a4)+, dO 

move.w 

dO,-<a7) 

jsr 

conout 

dbra 

d2,writltl 

move.1 

#trfrag6,aO 

jsr 

printf 

jsr 

emptybuf 

jsr 

wkey 

cmp.b 

#'Y 1 ,dO 

beq 

writlt2 

cmp.b 

#'y',dO 

bne 

writlten 

writlt2: move.w 

asector,-(a7 

move.w 

wside,-(a7) 

move.w 

wtrack,-(a7) 

move.w 

#1, -(a7) 

move.w 

wdrive,-(a7) 

clr. 1 

- (a7) 

move.1 

#spacetr,-(a 1 

move.w 

#9, -(a7) 

trap 

#14 

add. 1 

#20,a7 

tst .w 

dO 

bmi 

writlerl 

writlten: jsr 

cursmess 

jsr 

delline 

writltel: jsr 

cursmess 

move.1 

#trfragl,aO 


;* display sector number 


;* clear rest of line 

;* empty keyboard buffer 
;* and return 

;* write track back to disk 


;* output 34 bytes at mlsecta 
;* on the screen 


;* ask for confirmation to 
;* write to disk 
;* empty keyboard buffer 
;* read keyboard and check for 
;* upper and lowercase y 

;* if other key, then don't write 

;* number of sectors on stack 

;* current side 

;* current track 

;* start sector equals one 

;* current drive 

;* dummy long word 

;* buffer address 

;* Flopwr command on stack 

;* XBIOS trap 

;* restore stack 

;* did an error occur? 

;* yes 

;* no error, then clear status line 
;* and output message 


268 


Abacus 


Atari ST Disk Drives Inside and Out 


jsr 

printf 

move.1 

(a7) +, a4 

rts 


writlerl: move.w 

dO,-(a7) 

jsr 

errhand 

bra 

writltel 

end 



;* get a4 back 

;* error number on stack 
;* handle error 
;* and done 


Now for the Track with Sync menu routine. 


.*********************************************************************** 

r 

;* Subroutines for option TRACK with SYNCS. Routines do not access * 

;* any other routines, so this option can be implemented as desired. * 

.*********************************************************************** 

r 

.*********************************************************************** 

r 

;* first some often-used variables 

.*********************************************************************** 

r 


dmamode: 

equ 

$ff8606 

dmadat: 

equ 

$ff8604 

dmahigh: 

equ 

$ff8609 

dmamid: 

equ 

$ff860b 

dmalow: 

equ 

$ff860d 

mf p: 

equ 

$f f faOl 

flselec: 

equ 

$ff8800 

flwrite: 

equ 

$ff8802 

flock: 

equ 

$4 3e 


.*********************************************************************** 

f 

;* switch the processor into the supervisor mode. If the processor is * 
;* already in the supervisor mode, nothing happens. 
************************************************************************ 


move. 1 

#1,-(a7) 

. * 

/ 


move.w 

#$20,-(a7) 

;* GEMDOS function 

super 

trap 

#1 

;* test if already 

in super 

add. 1 

#6,a7 



tst .w 

dO 




269 


Abacus 


Atari ST Disk Drives Inside and Out 



bne 

superl 

;* processor already in super mode 


clr. 1 

~ (a7) 

;* if not, then swtich to 


move.w 

#$20,- (a7) 

;* supervisor mode 


trap 

#1 



add. 1 

#6,a7 



move.1 

dO,usstack 

;* store user stack 

superl: 

rts 


;* now in supervisor mode 

;******************************************************^^ jt ^^ it ^ i 

;* switch back 

to user mode 


;*****************************************************^^^^^ 

user: 

move.1 

#1, -(a7) 



move.w 

#$20,-(a7) 

;* GEMDOS function super 


trap 

#1 



add.l 

#6,a7 



tst .w 

dO 



beq 

userl 

;* already in user mode 


move.1 

usstack,-(a7) 



move.w 

#$20,-(a7) 



trap 

#1 



add.l 

#6,a7 


userl: 

rts 



fwait: 

dbra 

d7,fwait 



rts 


;* Reset the floppy disk controller (FDC) * 


flreset: jsr 

super 

move.w 

#$80,dmamode 

move.w 

#$d0,d6 

jsr 

wrcontr 

move.w 

#40,d7 

jsr 

fwait 

rts 


.****★************************ 

;* read the controller status 
****************************** 

rdcontr: jsr 

super 

move.w 

dmadat,d3 

jsr 

readcol 


;* switch to supervisor mode 
;* access the FDC register 
;* reset through interrupt command 
;* command to controller 
;* wait a bit 

;* and return 

****************************************** 
register and store it * 

****************************************** 

;* enable supervisor mode 
;* status register to D3 
; * wait a bit 


270 


Abacus 


Atari ST Disk Drives Inside and Out 


readcol: 


readco2: 


move. w 

sr, -(a7) 



move. w 

d7,-(a7) 

;* save 

timeout 

move. w 

#40,d7 



dbra 

d7, readco2 



move.w 

<a7)+,d7 

;* back 

again 

move.w 

(a7) +, sr 



rts 





* pass the number in D6 to the floppy disk controller * 


wrcontr: jsr 
jsr 

move.w 

jsr 

rts 


super 
readcol 
d6,dmadat 
readcol 


;* supervisor on 


;* wait a bit 


*********************************************************************** 
* read the FDC status register and store it in flstatus 
*********************************************************************** 


rdstatus: jsr 
jsr 

move. w 

jsr 

rts 


super 

readcol 

dmadat,flstatus 
readcol 


* supervisor on 

;* status in flstatus 

* wait a bit and 

* then return 


* select the current drive (red light on) 


seldrive 


select: 


jsr 

super 

• ★ 
t 

supervisor on 

move.w 

wdrive,dO 

• ★ 
t 

current drive 

cmp .w 

#1, dO 

• ★ 
t 

greate than 1 

bgt 

seldrend 

• ★ 
t 

if yes, then return 

addq.b 

#1, dO 

• ★ 

else combine with current side 

lsl.b 

o 

T3 

«-1 
=#= 



or .w 

wside,dO 



eor .b 

-J 

a 

o 



and.b 

#7, dO 



move.w 

sr,-(a 7) 



or .w 

#$700,sr 

• ★ 
r 

disable interrupt, because 

move.b 

#$e,flselec 

• ★ 
r 

the interrupt deselects 

move.b 

flselec,dl 

. ★ 
t 

the drives 

and.b 

#$f8,dl 



or .b 

dO, dl 




271 





Abacus 


Atari ST Disk Drives Inside and Out 


move.b dl,flwrite ;* pass to ACIA 

move.w (a7)+,sr ;* get status register back 

seldrend: rts ;* and return 

.***************************************************** ^j^*****^*^^^ 

;* deselect current drive (red light off) * 

;* the timing between floppy reset and deselecting must be right or * 

;* the disk motor will still run. * 

.*********************************************************************** 

deselect: jsr super ;* supervisor on 

move.w #$80,dmamode ;* select FDC register 
move.b #7,d0 

jsr select ;* deselect 

rts ;* and return 

************************************************************************ 
;* read an entire track with all syncs into the buffer that starts * 

;* at the address spacetr * 

.*********************************************************************** 


rdstrack: jsr super 

clr.l currdma 

move.w sr,varw3 

move.w #$2700,sr 

move.w #$90,dmamode 

register 

move.w #$190,dmamode 
move.w #$90,dmamode 
move.w #$16,d6 

move.w #512,d2 

mulu d6,d2 

move.w d2,maxhead 

add.l #spacetr,d2 

move.l d2,topdma 

jsr wrcontr 

move.l #spacetr,dO 

move.b d0,dmalow 

lsr.l #8,d0 

move.b d0,dmamid 

lsr.l #8,dO 

move.b dO,dmahigh 

move.w #$80,dmamode 
move.w #$e8,d6 

jsr wrcontr 

move.l #$50000,d7 


;* supervisor on 

;* save old status register 
;* disable interrupts; not actually 
;* necessary, switch sector count 

;* toggle DMAMODE to read 
;* and clear the DMA register 
;* 22*512 bytes will be read 
;* (although there aren't that 
;* many on the diskette) 

;* calculate the DMA end address 
;* store it 

;* d6 (number of sectors) to FDC 
;* pass address of the DMA buffer 
;* to the DMAC 


;* select FDC register 
;* read-track command to the FDC 
;* pass it 
;* timeout counter 


272 


Abacus 


Atari ST Disk Drives Inside and Out 


move.l topdma,a5 ;* 

move.w #$200,dO ;* 

rdl: dbra d0,rdl 

rdstrll: btst #5,mfp ;* 

beq rdtrendl ;* 

subq.l #l,d7 ;* 

beq rdtrerrl ;* 

move.b dmahigh,highdma;* 
move.b dmamid,middma ;* 
move.b dmalow,lowdma ;* 
cmp.l currdma,a5 ;* 

bgt rdstrll 

rdtrendl: move.w #$90,dmamode ; * 

move.w dmamode,d5 ;* 

move.w d5,dmastat ;* 

btst #0,d5 

beq rdtrerr2 

move.w #$80,dmamode ;* 
jsr rdstatus ;* 

rdtend: move.w varw3,sr ;* 

rts ;* 


DMA end address 
wait a bit 

command already processed? 
if so, then end 

else decrement timeout counter 
if counter run out, then error 
test if end DMA address already 
reached; is unnecessary because the 
controller stopped earlier (fewer 
bytes on the disk) 

switch to sector count register 
read status of the DMA chip 
and store 

switch to FDC register 
read FDC status 

get status register back 
and return 


rdtrerr2: bra rdtend 


rdtrerrl: bra rdtend 

.********************************************************************** 

r 

;* Place the read/write head on the track passed in wtrack 

.********************************************************************** 

r 


searcht: jsr super 

jsr trackO 

move.w #$86,dmamode 
move.w wtrack,d6 
jsr wrcontr 

move.w #$80,dmamode 
move.w #$lb,d6 

jsr wrcontr 

move.l #$60000,d7 
searchl: subq.l #l,d7 

beq searendl 

btst #5,mfp 

bne searchl 

rts 


;* supervisor on 
;* seek track zero 
;* select track register 
;* current track to track register 

;* select FDC register 
;* search track command 
;* pass to controller 
;* timeout counter 

;* command aleady processed? 

;* no, keep waiting 


273 


Abacus 


Atari ST Disk Drives Inside and Out 


searendl: raove.w #-7,-(a7) ;* error = no disk 

jsr errhand 

rts 


;* Seek track zero * 


trackO: move.w 

and.w 
move.1 
move.w 
jsr 


seek,d6 
#3,d6 

#$50000,d7 
#$80,dmamode 
wrcontr 


;* seek rate 

;* combine with track-zero command 
;* timeout counter 
;* access FDC register 
;* pass command 


trackOll: subq.l 
beq 
btst 
bne 
rts 


#1, d7 
trackOer 
#5,mfp 
trackOll 


;* decrement counter 
;* timeout 
;* FDC ready? 

;* no, keep waiting 
; * and return 


trackOer: move.w #-7,-(a7) 
jsr errhand 

rts 


;* pass error number to 
;* error handler 
;* and return 


;* Pass the address of the buffer spacetr to the DMA controller * 


move.1 

#spacetr,dO 

move.b 

dO,dmalow 

lsr. 1 

=#= 

00 

a 

o 

move.b 

dO,dmamid 

lsr .1 

#8, dO 

move.b 

rts 

dO,dmahigh 


;*********************************************************************** 
;* Read track with all syncs control routine, calls all necessary * 

;* subroutines * 

;*********************************************************************** 


rdtracks: movem.l 
jsr 
jsr 
jsr 

move.1 


a3-a6/d3-d7,-(a7) 
cursmess 
delline 
cursmess 

#trfrag2,a0 ;* 


;* save registers 


output message 


274 




Abacus 


Atari ST Disk Drives Inside and Out 


jsr 

printf 



move . w 

#18, lincount 

• ★ 

/ 

for subroutine Dispbuf = 

jsr 

super 

• ★ 
r 

supervisor on 

st 

flock 

• ★ 
r 

floppy interrupt off 

jsr 

seldrive 

• ★ 
f 

select drive 

jsr 

flreset 

• * 
f 

reset controller 

jsr 

searcht 

• ★ 
r 

seek current track 

jsr 

rdstrack 

• ★ 
f 

read track twice 

jsr 

rdstrack 



jsr 

flreset 

• ★ 
r 

reset FDC 

jsr 

user 

• ★ 
t 

user mode on 

jsr 

shtracks 

• ★ 
t 

display this track 

jsr 

super 

• ★ 
r 

supervisor on 

jsr 

deselect 

. * 

/ 

deselect floppy 

sf 

flock 

. * 
r 

release floppy interrupt 

jsr 

user 

• ★ 
r 

enable user mode 

movem . 1 

(a7)+,a3-a6/d3 

-d7 

;* get registers back 

rts 


. * 

/ 

and return 


;* Pass the parameters for displaying the track to the general showit * 
;* routine * 
• *★****★*★*★*★★★*★****★**★*★★*★****★★**★★*★★****★★★*★★★★***★****■*•***■*■*** 


move.w 

#0,head2 



move. 1 

fspacetr,topptr 



move. w 

#18,lincount 

• ★ 
r 

19 lines on the screen 

move.w 

#100,prcount 

• ★ 
r 

101 lines to print 

move, w 

#7680,maxdown 



move. w 

#7888,maxup 



jsr 

cursbuf 



jsr 

clrest 

• ★ 

/ 

clear rest of screen 

jsr 

showit 

• ★ 
r 

display buffer, with handle 

jsr 

emptybuf 

• ★ 
r 

cursor keys, etc. 

rts 





• ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A - ** * 

;* read address fields on the disk * 

• ★******★★★*★★***★**★**★*★**★*★★**★**★★*★★★*★★*★*★'*'★★*'*■**★****■*■*•*•■*•*■■>. * * * 


jsr 

cursmess 

;* position cursor 

jsr 

delline 

;* delete line 

move. 1 

#hilcurs,aO 

;* output message 

jsr 

printf 


move.w 

wdrive,dO 


cmp .w 

#2, dO 


bgt 

rdaderr 



275 





Abacus 


Atari ST Disk Drives Inside and Out 


jsr 

super 

• ★ 
r 

jsr 

seldrive 

. * 

jsr 

flreset 

. * 
r 

jsr 

searcht 

• ★ 
r 

jsr 

searcht 

• ★ 

jsr 

setspace 

• * 
t 

jsr 

rdadr 

• ★ 
t 

jsr 

flreset 

• ★ 

jsr 

user 

• ★ 
t 

jsr 

showadr 

. * 
r 

jsr 

super 

• •k 
r 

jsr 

deselect 

• ★ 
r 

jsr 

user 

• ★ 
r 

rts 


• ★ 
r 


/ 

;* Read 25 address fields from the 

• ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A* 


supervisor on 
select current drive 
FDC reset 

seek current track twice 
so the drive is ready 
set DMA transfer address 
read address fields 
FDC reset 
user mode on 
display address fields 
supervisor on 
deselect current drive 
user mode on 
and return 

★★★★*★★★**★★★★★★★★★★★★★★★★★★★★★★★★ 
disk * 


rdadr: jsr 

super 

move.w 

#$90,dmamode 

move.w 

#$190,dmamode 

move.w 

#$90,dmamode 

move.w 

#1, d6 

jsr 

wrcontr 

move.w 

#$80,dmamode 

move.w 

#24,d4 

rdadr1: move.w 

#$c8,d6 

move.1 

#$40000,d7 

jsr 

wrcontr 

rdadr2: btst 

#5,mfp 

beq 

rdadrenl 

subq.1 

#1, d7 

beq 

rdaderr 

bra 

rdadr2 

rdadrenl: dbra 

d4,rdadr1 

rts 


rdaderr: move.w 

#-6,-(a7) 

jsr 

errhand 

rts 



* enable supervisor mode 

* toggle the read/write line 

* clear the DMA status, reset DMA 

* switch to read and sector count 

* register, read 1 sector 

* to FDC controller 

* switch to FDC register 

* read 24+1 address fields 

* read-address command 

* timeout counter 

* command to FDC 

* command already processed? 

* yes 

* else decrement timeout 

* timeout?, then error 

* else keep waiting 

* repeat 25 times 

* and return 

;* error message 
;* output, and terminate 


•★★★**★★★★***★*★★**★**★★★★**★★*★**★★*★**★★*★★*★★**★******★*★★★★★★*★★★★★* 
r 

;* Display the address fields read. More address fields are read than * 
;* are displayed because the DMA controller transfers the bytes in * 

;* groups of 16, whereas an address field contains only 6 bytes. * 

r 


276 







Abacus 


Atari ST Disk Drives Inside and Out 


showadr: 


showadrl 


showadr2 


showadr7 


jsr 

cursmess 

★ 

position cursor and delete and 

jsr 

delline 

★ 

output message 

move. 1 

#sadfragl,aO 



jsr 

printf 



jsr 

cursbuf 

★ 

position cursor 

move.w 

#17,d5 

★ 

display 18 address fields 

move.1 

#spacetr,a3 

★ 

buffer address of the address fields 

move.w 

#2,d4 

* 

output 3 data (track, side. 

move. w 

#$20,-<a7) 

★ 

sector), first output a space 

jsr 

conout 



move.b 

(a3) +, dO 

★ 

get byte from buffer 

move. w 

d0,-(a7) 

* 

move to stack as word 

jsr 

dezpr 

★ 

and output in decimal 

move.w 

#$20,-<a7) 

★ 

two spaces after it 

jsr 

conout 



move.w 

#$20,-(a7) 



jsr 

conout 



dbra 

d4,showadr2 

★ 

repeat three times 

move.w 

#$20,-(a7) 

★ 

then write 2 spaces 

jsr 

conout 



move.w 

#$20,-(a7) 



jsr 

conout 



move.b 

(a3) +, dO 

★ 

next byte from buffer (contains 

ext. w 

dO 

* 

the sector size) 

move.w 

#128,dl 

■k 

a 0 means 128 bytes/sector 

cmp.w 

#0, dO 



beq 

showadr7 



move.w 

#256,dl 



cmp.w 

#1, dO 

k 

1 means 256 bytes/sector 

beq 

showadr7 



move.w 

#512,dl 



cmp.w 

#2, dO 

k 

2 means 512 bytes/sector 

beq 

showadr7 



move.w 

#1024,dl 

’ * 

else 1024 bytes/sector as default 

move.w 

dl,-(a7) 

* 

output number of bytes/sector 

jsr 

dezpr 

• ★ 

in decimal 

move.w 

#$20,- (a7) 

* 

output spaces 

jsr 

conout 



move.1 

ispaces,aO 



jsr 

printf 



move.b 

(a3) +, dO 

k 

next byte in buffer is the checksum 

move.w 

dO,-(a 7) 

k 

of the address field, which is 

jsr 

hexpr 

k 

printed as a hex number 

move.b 

(a3) +, dO 

k 

next byte from buffer 

move.w 

dO,-(a7) 



jsr 

hexpr 

• k 

as hex number 


277 






Abacus 


Atari ST Disk Drives Inside and Out 


move. w 

#13,-(a7) 

• * 
t 

jsr 

conout 


move.w 

#10,-(a7) 


jsr 

conout 


dbr a 

d5,showadrl 

• ★ 
f 

jsr 

wkey 

. * 
t 

rts 


• ★ 
f 

end 




carriage return plus linefeed 


repeat 18 times 

and wait for keypress 

and back 


Next is the Cluster menu subroutine. 


r 

;* Subroutines for the option CLUSTER. The routines access routines * 

;* from the OPTION menu, so OPTION must be implemented first. * 

•***★★*★**★**★★*★**★*★**★★***★**★★**★*★********★**★★★★**★★★★**★*★*★★★★★★ 

r 


jsr 

cursmess 

• ★ 

! 

cursor pos., etc. 

jsr 

delline 



move. w 

#20,column 



move. w 

#2,line 



jsr 

loccurs 



move. 1 

#edfragl,aO 

• * 
r 

message 

jsr 

printf 



move. w 

#512,maxdown 

• ★ 
t 

scroll up and down variables 

move.w 

#720,maxup 



move.l 

#spacetr,editptr 

;* buffer address 

jsr 

editit 

. * 
r 

edit cluster 

jsr 

cursmess 

• ★ 
r 

delete message line 

jsr 

delline 



jsr 

cursmess 



move . 1 

#clfragl,aO 

• * 
t 

output message 

jsr 

printf 



jsr 

curleft 

• * 
r 

left three times 

jsr 

curleft 

• * 
f 

to jump into read 

jsr 

curleft 

• ★ 
f 

submenu 

jsr 

shclust 

• ★ 
r 

display the cluster 

rts 


• * 
t 

and return 


r 

;* decrement the cluster number in the cluster menu * 

.*********************************************************************** 

r 


decclust: move.w 
move. w 
trap 
addq.1 


#-l,-(a7) 

#ll,-(a7) 

#13 

#4,a7 


;* test keyboard shift 
;* if shift pressed 
;* then decrement is 10 


278 




Abacus 


Atari ST Disk Drives Inside and Out 


decclshi: 
declstO: 


declstl: 
declst2: 


incclust 


btst 

#0, dO 

★ 

else decrement by one 

bne 

decclshi 



btst 

#1, dO 



bne 

decclshi 

★ 

shift pressed 

move. w 

#1, d2 

★ 

else not pressed. 

bra 

declstO 

★ 

so decrement by one 

: move. w 

#10,d2 

★ 

decrement by 10 

move.w 

wclust,d0 

★ 

current cluster number 

sub .w 

d2,d0 

★ 

subtract decrement 

cmp. w 

#0, dO 

★ 

less than 0 

bit 

declstl 

★ 

yes 

bra 

declst2 

* 

no 

move. w 

maxclust,dO 

★ 

max cluster number as new current 

move. w 

dO,wclust 

* 

cluster number 

ext .1 

dO 

★ 

the new cluster number must also be 

divu 

#1000,dO 

★ 

entered in the menu 

add.b 

#'0',dO 

★ 

se we split it into powers of ten 

move.b 

dO,mlclusal 

★ 

and put it in the cluster menu 

swap 

dO 



ext. 1 

dO 



divu 

#100,dO 



add.b 

#' 0 1 , dO 



move.b 

dO,mlclusal+1 

★ 

enter 100's 

swap 

dO 



ext .1 

dO 



divu 

#10,dO 



add.b 

# ' 0 ', dO 



move.b 

dO,mlclusal+2 

• ★ 

enter 10's 

swap 

dO 



add.b 

=*= 

o 

a 

o 



move.b 

d0,mlclusal+3 

• ★ 

and finally the 1'2 in the menu 

jsr 

dispmen 

• ★ 

display menu and 

rts 


• ★ 

return 

*************************************************************** 

■ement the 

current cluster 

number 

*************************************************************** 

: move.w 

#-l,-(a7) 



move.w 

#11,-(a7) 

. ★ 
r 

test keyboard shift 

trap 

#13 

. * 
t 

as for decclust 

addq.1 

#4, a7 



btst 

#0, dO 



bne 

incclshi 



btst 

#1, dO 



bne 

incclshi 



move.w 

#1, d2 

. * 
r 

no shift key, then 1 as 


279 





Abacus 


Atari ST Disk Drives Inside and Out 


bra inclstO 

incclshi: move.w #10,d2 

inclstO: move.w wclust,d0 
add.w d2,dO 

cmp.w maxclust,dO 
bit inclstl 

move.w #0,d0 

inclstl: move.w dO.wclust 
ext.l dO 

divu #1000,dO 

add.b #'0 1 ,dO 

move.b dO,mlclusal 
swap dO 

ext.l dO 

divu #100,dO 

add.b # 1 0',dO 

move.b dO,mlclusal+l 
swap dO 

ext.l dO 

divu #10,dO 

add.b #'0 1 ,dO 

move.b dO,mlclusal+2 
swap dO 

add.b # 1 0 1 ,dO 

move.b dO,mlclusal+3 
jsr dispmen 

rts 


;* increment 

;* else increment equals 10 
;* add increment to current cluster 
;* number and compare with maximum 
;* number 

;* less than maximum number 

;* store new current number 
;* and enter current number in menu 
;* 1000's place 

;* enter 1000's place 


;* enter 100's place 


;* enter 10's place 

;* 1 1 s place 
;* display menu and 
;* return 


.*********************************************************************** 

t 

;* Find the next cluster following the current cluster. If this is * 
;* the last cluster, this is indicated. * 

r 


move.w 

wclust,d0 

move. w 

dO,oldclst 

jsr 

findclst 

move. w 

newclst,dO 

tst .w 

dO 

beq 

neclerrl 

cmp.w 

#$ff8,dO 

bge 

neclerrl 

subq.w 

#1, dO 

move.w 

dO,wclust 

move.1 

#3,revnum 

jsr 

incclust 

jsr 

rdclust 


;* current cluster number 
;* store 

;* find next cluster 

;* here is next cluster 

;* or a 0, which signals an error 

;* or an end marker, which 

;* indicates the last cluster 

;* subtract one for better handling 

;* of the menu display 

;* the incclust routine can be called 

;* which displays the incremented 

;* cluster 

;* and then reads this cluster 


280 




Abacus 


Atari ST Disk Drives Inside and Out 


neclend: rts 


neclerrl 

: jsr 

cursmess 


move.w 

#-19,-<a7) 


jsr 

errhand 


jsr 

cursmess 


move. 1 

#clfragl,aO 


jsr 

printf 


bra 

neclend 

findclst 

: move.1 

#fatbuf,aO 


move. w 

oldclst,dO 


move. w 

#3, dl 


mulu 

dO, dl 


lsr .w 

#1, dl 


btst 

#0, dO 


bne 

codd 

ceven: 

move. b 

1(a0,dl.w),dO 


lsl. w 

#8, dO 


or .b 

0(aO, dl.w),dO 


and.w 

#$0fff,d0 


move. w 

dO,newclst 


bra 

ficlend 

codd: 

move.b 

1(aO, dl.w),dO 


lsl .w 

#8, dO 


move. b 

0(a0,dl.w),dO 


lsr .w 

#4, dO 


and.w 

#$0fff,d0 


move. w 

dO, newclst 

ficlend: 

rts 


• ★******★*★*★*★* 


;* write the current cluster t< 

.*********************★*★******• 

wrclust: 

movem. 1 

a3-a5/d3-d5,- 


move. w 

#0, column 


move. w 

#2,line 


jsr 

loccurs 


move.1 

#clfrag5,aO 


jsr 

printf 


move. 1 

#mlsecta,a3 


move.w 

#9,d3 

wrcll: 

move. b 

(a3)+,dO 


move. w 

dO, -(a7) 


jsr 

conout 


dbra 

d3,wrcll 


;* announce last cluster as such 


;* and return 

;* address of the FAT buffer 
;* old cluster number 
;* times 3, and 

* divide by 2, equals times 1.5 

* was old cluster # even or odd 

* (divisible by 2 or not) 

* if even, the get most significant 

* nibble, shift 8 bits to the left 

* and OR the two remaining nibbles 

* to it 

* store as new cluster number 

* and return 

* else: get most significant nibble and 

* shift 8 bits to the left 

* least significant nibble 

* the upper 12 bits contain the 

* cluster number, so mask out 

* 4 bits on the right, store 

* and return 


;* output message 


;* current track 


281 




Abacus 


Atari ST Disk Drives Inside and Out 


wrcl2: 


writclst: 


wrclend: 


wrclster 


wrclendl 


move . 1 

♦mlclusa,a3 

• ★ 

output cluster as question 

move . w 

#12 , d3 



move . b 

<a3) +, dO 



move . w 

dO, - (a7) 



jsr 

conout 



dbra 

d3 , wrcl2 



move . X 

#wrfrag2 , aO 



jsr 

printf 



jsr 

emptybuf 



jsr 

wkey 

• ★ 
t 

really write 

cmp .b 

#'y 1 , dO 

• ★ 
t 

yes 

beq 

writclst 



cmp.b 

# ' Y 1 , dO 

. * 
t 

yes 

bne 

wrclendl 

. * 
r 

else don't write 

move . w 

wdrive, - (a7) 

• ★ 
f 

pass current drive 

move . w 

wclust , dO 

• ★ 

/ 

current cluster number 

sub.w 

#2 , dO 

• ★ 
r 

number 2 is first data cluster 

muls 

clsiz,dO 

• ie 
/ 

calculate logical sector number 

add .w 

datrec,dO 



move . w 

d0,-(a7) 

. * 
r 

logical sector number on ST 

move . w 

clsiz, - (a7) 

• ★ 
f 

number of sectors per cluster 

move . 1 

#spacetr, — (a 7) 

• * 

! 

start address of the cluster 

move.w 

#3,-(a7) 

• ★ 

/ 

write, ignore disk change 

move.w 

#4, -(a7) 

• ★ 

Rwabs 

trap 

#13 

. ★ 
f 

BIOS trap 

add. 1 

#14,a7 

• ★ 

restore stack 

tst .w 

dO 

• ie 
r 

error occurred 

bmi 

wrclster 

• * 
r 

yes, then handle 

jsr 

cursmess 



jsr 

delline 

• ★ 
f 

else output message 

jsr 

cursmess 



move.1 

#clfragl,aO 



jsr 

printf 



movem.1 

(a7)+,a3-a5/d3 

-d5 

;* restore registers 

rts 


• ie 
/ 

and return 

: move.w 

dO, -(a7) 

. ★ 
r 

error number to 

jsr 

errhand 

. * 
r 

error handler and display 

bra 

wrclend 

• ★ 
r 

and return 

: jsr 

cursmess 



jsr 

delline 



jsr 

cursmess 



move. X 

#wrfrag3,aO 



jsr 

printf 



jsr 

emptybuf 



jsr 

wkey 




282 





Abacus 


Atari ST Disk Drives Inside and Out 


jsr delline 
bra wrclend 
rts 


************************************************************************ 

;* Read the current cluster into memory, also works with RAM disk. * 
•*********************************************************************** 


rdclust: 
rdclO: 


rdcl2: 


rdcl3: 
rdcl4 : 


rdclend: 


movem . 1 

a3-a6/d3-d7,-(a7) 

;* save registers 

move.w 

wdrive,-(a7) 

★ 

current drive 

move.w 

wclust,dO 

★ 

current cluster 

subq.w 

#2, dO 

★ 

calculate logical sector number 

mu Is 

clsiz,dO 



add.w 

datrec,dO 



tst .w 

dO 



bpl 

rdcl2 

★ 

greater than zero 

move.w 

#0, dO 

★ 

if not, then zero 

move. w 

dO,logsect 

★ 

store logical sector 

move. w 

dO, -(a7) 

★ 

and on stack 

move . w 

#2,-(a7) 

★ 

read 2 sectors 

move . 1 

#spacetr, - (a7) 

* 

buffer address 

move.w 

#0, - (a7) 

★ 


move . w 

#4, - (a7) 

* 

Rwabs command 

trap 

#13 

★ 

BIOS trap 

add.l 

#14,a7 

k 

restore stack 

tst .w 

dO 

★ 

did an error occur? 

bmi 

rdclster 

■k 

if so, then display 

move . w 

logsect,dO 

k 

convert logical sector to physical 

divs 

#9, dO 



swap 

dO 



addq.w 

#1, dO 

k 

add one to remainder of division 

move . w 

dO,wsector 

k 

equals physical sector 

swap 

dO 



move . w 

d0,d2 

k 

store result of division 

move . w 

#0,wside 

k 

side zero as default 

move . w 

numsides,dl 

• k 

number of sides 

cmp. w 

#2, dl 

k 

if 2 sides. 

bne 

rdcl3 



lsr .w 

#1, dO 

• k 

then divide by 2 

btst 

#0, d2 

k 

test if result odd 

beq 

rdcl4 

k 


move.w 

#1,wside 



move.w 

dO,wtrack 

k 

equals physical sector 

jsr 

secinmem 

k 

sector into memory 

jsr 

shclust 

' * 

display cluster 

jsr 

cursmess 




283 





Abacus 


Atari ST Disk Drives Inside and Out 


move.l #clfragl,aO 
jsr printf 

movem.l (a7)+,a3-a6/d3 
rts 

rdclster: jsr initdriv 

tst.l dO 
bne rdclO 

move.w d0,-(a7) 
jsr errhand 

bra rdclend 

secinmem: move.w wside,dO 
add.b # 1 0',dO 
move.b dO,mside 
move.w wsector,dO 
ext.1 dO 

divs #10,dO 

add.b #'0 1 ,dO 
move.b dO,msector 
swap dO 

add.b #'0 1 ,dO 
move.b dO,msector+l 
move.w wtrack,dO 
ext.1 dO 

divs #10,dO 

add.b # 1 0',dO 
move.b dO,mtrack 
swap dO 

add.b #'0 1 ,dO 
move.b dO,mtrack+l 
rts 


;* output message 

d7 ;* restore registers 
;* and return 

;* if error occurred, then 
;* initialize first drive 
;* if no error, then again 

;* must be changed 

;* transfer current sector into 
;* sector menu for later display 


;* low byte of sector 


;* low byte of track 


•***★★★★★*★*★**★ 

;* Display the cluster 






shclust: move.w #0,head2 ;* byte counter 

move.w #18,lincount ;* display 19 lines 

move.w #63,prcount ;* 64 lines for printer output 

move.l #spacetr,topptr ;* buffer address 

move.w #512,maxdown ;* scroll limit 

move.w #720,maxup 

jsr cursbuf ;* position cursor and 

jsr clrest ;* clear rest of screen 

move.w #0,column ;* cursor to last screen line 

move.w #24,line 


284 


Abacus 


Atari ST Disk Drives Inside and Out 


jsr 

loccurs 

move.1 

#clfrag2,aO 

jsr 

printf 

jsr 

showit 

rts 



;* position 

; * display the cluster 
;* return 


★*★***★***★★★**★**★★********★***★****★**★*****★*****★★***************** 

* Display the first cluster of the file on the disk. Start cluster * 

* is accepted as the cluster number in the menu by pressing <return>.* 

* If the filename in reverse is a subdirectory, this must first be * 

* entered. * 

*********************************************************************** 


jsr 

initdriv 

• ★ 
t 

initialize drive 

jsr 

rdf at 

• ★ 

/ 

read FAT and directoi 

jsr 

rddir 

• ★ 
t 

into the buffer 

move.w 

#0,column 



move.w 

#2,line 



jsr 

loccurs 

. * 

/ 

position cursor 

move. 1 

#sclfragl,aO 



jsr 

printf 



move.w 

#17,lincount 

• ★ 

/ 

display 18 lines 

jsr 

delrest 

• ★ 
t 

delete rest of line 

move.1 

#dirbuf,a3 

• * 
t 

store address of 

move.1 

a3, a4 

. ★ 
t 

directory buffer 

move.1 

a3,topptr 

• -k 

r 

use as pointer 

move. 1 

a3,oldtop 

• ★ 
r 

store cursor 

jsr 

cursbuf 

• ★ 

/ 

again 

jsr 

showdir 

. * 
t 

display 18 lines 

jsr 

cursbuf 

. * 
r 

cursor to start 

move.1 

#dirbu f,t oppt r 

• * 
r 

start of directory bi 

jsr 

revon 

• * 
r 

turn on reverse 

jsr 

dirline 

• ★ 
r 

first filename (disk 

jsr 

revout 

• ★ 
r 

write in reverse, th 

jsr 

key 

• ★ 
r 

and read keyboard 

swap 

dO 



cmp .b 

#$lc,dO 

• ★ 

/ 

Return key pressed? 

beq 

dirclsel 

• ★ 
r 

yes 

cmp.b 

#$48,dO 

• * 
t 

cursor up? 

beq 

stclup 

• ★ 
r 

yes 

cmp.b 

#$50,dO 

• ★ 
r 

cursor down? 

beq 

stcldo 

• ★ 
f 

yes 

cmp.b 

#$4b,dO 

• ★ 
r 

cursor left? 

beq 

stclli 

• ★ 
r 

yes 

cmp. b 

#$4d,dO 

• ★ 

/ 

cursor right 

bne 

stclstl 




285 




Abacus 


stclli: 

stclup: 


stclup3: 


stclupen 
stcldo: 


Atari ST Disk Drives Inside and Out 


jsr 

curright 

. * 
f 

yes, then call 

bra 

stclendl 



jsr 

curleft 



bra 

stclendl 



move. w 

line,dO 

• ★ 
r 

current cursor line 

cmp .w 

=#= 

a 

o 

• ★ 
r 

line 4 equals upper border 

ble 

stclup3 

• * 

! 

equals 4, then scroll 

move. w 

#0,column 



jsr 

loccurs 



jsr 

dirline 

• * 
r 

else subtract one from 

subq.w 

#1,line 

• ★ 
r 

the current line, cursor 

move. w 

#0,column 

. * 
t 

to the new line and set 

jsr 

loccurs 

• ★ 

column to zero 

jsr 

revon 



jsr 

dirline 

• ★ 
r 

and display this line in reverse 

jsr 

revout 

• ★ 

turn reverse off 

bra 

stclupen 

• ★ 
r 

and return 

cmp. 1 

tdirbuf,topptr 

• ★ 
t 

top line in buffer reached? 

beq 

stclupen 

• ★ 

/ 

if so, then don't scroll 

move.1 

topptr,dO 

. ★ 

/ 

else decrement ptr by number of lines 

move.w 

lincount,dO 

• ★ 
t 

times number of characters per line 

addq.w 

a 

O 

. * 
r 

changed 8/18/86 

muls 

#32,dO 



sub.l 

dO,topptr 

• ★ 

decrement pointer in buffer 

jsr 

showdir 

• * 

/ 

display 18 lines 

move.w 

#21,line 



move.w 

#0,column 

• ★ 

last displayed line reverse 

jsr 

loccurs 

• ★ 
r 

cursor pos. 

jsr 

revon 

• ★ 
r 

reverse on 

jsr 

dirline 

• * 
t 

display line 

jsr 

revout 

• * 
! 

reverse off again 

: bra 

stclstl 

• ★ 
t 

to loop 

move.w 

line,dO 

. * 
r 

current line greater than 20 

cmp .w 

#20,dO 



bgt 

stcldo3 

• ic 
r 

yes 

move. w 

line,dO 

• ★ 
t 

if not, then add 1 

addq.w 

#1 , dO 

• * 
f 


sub.w 

#4, dO 

• * 
f 

offset to upper screen border 

ext. 1 

dO 



lsl.l 

#5, dO 

• ★ 
r 

multiply by 32 

move. 1 

topptr,a6 

. * 
t 

pointer in directory buffer 

move.b 

0(a6,dO.1),dO 

• ie 
t 

get first byte of this entry 

beq 

stcldoen 

• ★ 
r 

if byte=0, then empty entry 

move.w 

#0,column 

. * 
r 

else position cursor and 


286 



Abacus 


Atari ST Disk Drives Inside and Out 



jsr 

loccurs 



jsr 

dirline 

• * 
r 


addq.w 

#1,line 

• * 
r 


move.w 

#0,column 



jsr 

loccurs 



jsr 

revon 

• ★ 
t 


jsr 

dirline 

• ★ 
/ 


jsr 

revout 

• * 
r 


jsr 

loccurs 


stcldol: 

bra 

stcldoen 

• * 
r 

stcldo3: 

move.w 

line,dO 

• ★ 
t 


addq.w 

#1, dO 

• * 
r 


sub .w 

#4, dO 

• ★ 
r 


ext. 1 

dO 



lsl.l 

#5, dO 

• k 
r 


move.1 

topptr,a6 

• ★ 
t 


move.b 

0(a6, dO.1),dO 

• * 
f 


beq 

stcldoen 

• ★ 
! 


move.w 

lincount,dO 

• ★ 
t 


addq.w 

#1, dO 

• ★ 
f 


muls 

#32,dO 

• ★ 
t 


add.l 

topptr,dO 

• ★ 
r 


move.1 

dO,topptr 



jsr 

cursbuf 

• * 
f 


jsr 

showdir 

• ★ 
r 


jsr 

cursbuf 

• ★ 
t 


jsr 

revon 



jsr 

dirline 

• ★ 
t 


jsr 

revout 


stcldoen 

: bra 

stclstl 

• * 
r 

stclendl 

: jsr 

cursmess 

• ★ 
/ 


jsr 

delline 



jsr 

cursmess 



move.1 

#clfragl,aO 

• * 
r 


jsr 

printf 



movem.1 

(a7)+,a3-a5/d3- 

-d7 


rts 


• -k 

t 


display old line normal 
increment line counter and 

display new line 
in reverse 

turn reverse off again 
to loop 

get first byte of the next directory 
entry, add one and subtract 
offset to top 

times 32 (# of bytes/directory entry) 

pointer to start of dir buffer 

is the next entry zero? 

then back to loop 

number of lines to display 

plus one times 

32 equals offset from start of buf 
add offset to topptr 

pos. cursor 
display directory 
first entry in reverse 

display 

back to loop 

delete message line 

display mode 

;* restore registers 
and return 


.★****★★★★**★★**★★★★***********★*★★★★*★***★★*★**★*★*★★★**★★★★**★***★*★** 
;* reacts to pressing of Return key, accepts it or displays a * 

;* subdirectory. * 

. ★*************★*★******★************************■*********************.*.* 

dirclsel: move.l topptr,aO ;* ptr to current start of buffer 

line,dO 


move.w 


287 




Abacus 


Atari ST Disk Drives Inside and Out 


dirsell: 


dirsel2: 


subdir: 


number 


subdir1: 


sub.w 

#4, dO 

• ★ 
t 


ext. 1 

dO 



lsl.l 

#5,dO 

• * 

times 32 

move.b 

11(aO,dO.1), dl 

• ★ 
r 

get file type byte 

cmp.b 

#$10,dl 

• ★ 
r 

is it a subdirectory? 

beq 

subdir 

• ★ 
t 

yes 

move. w 

clstnum,dO 

• ★ 
r 

else current cluster number 

subq.w 

#1, dO 

• ★ 
r 

subtract 1 for incclust 

move. w 

dO,wclust 



move.1 

#3,revnum 

• ★ 
f 

3rd menu option in reverse 

jsr 

incclust 

• ★ 
f 

increment cluster number and display 

bra 

stclendl 

• ★ 

/ 

menu, then back to loop 

jsr 

rddir 

• ★ 
t 

read directory sectors 

bra 

subdiren 



tst .w 

clstnum 

• ★ 

/ 

if cluster number is zero then just 

beq 

dirsel2 

« * 

reread directory sectors 

move.w 

clstnum,dO 

• * 
f 

else read at the initial cluster 

move.1 

#dirbuf,dirptr 



clr .w 

d3 



move.w 

clstnum,dO 



move.w 

wdrive,-(a7) 

• ★ 

/ 

current drive 

subq.w 

#2, dO 

• * 

/ 

convert cluster number to 

muls 

clsiz,dO 

• ★ 
f 

logical sector number 

add.w 

datrec,dO 



move.w 

dO,-<a7) 



move.w 

#2,-(a7) 

• ★ 

/ 

read 2 logical sectors 

move.1 

dirptr,-(a7) 

• ★ 
r 

buffer address 

move.w 

#2,-<a7) 

• ★ 

/ 

read 

move„w 

#4,-(a7) 

• * 
t 

BIOS Rwabs 

trap 

#13 

• ★ 
t 

BIOS Trap 

add.l 

#14,a7 



tst .w 

dO 

• ★ 

error occurred? 

bmi 

subdierr 

• ★ 

/ 

yes, then handle 

add.l 

#1024,dirptr 

• ★ 

/ 

else add 1024 bytes per cluster 

move.w 

clstnum,oldclst 

;* store cluster number 

jsr 

findclst 

• ★ 
r 

and find next cluster 

move. w 

newclst,dO 



move. w 

dO,clstnum 



tst .w 

dO 

• ★ 
r 

next cluster found? 

beq 

subdiren 

• ★ 
t 

if not, then end 

cmp .w 

#$ff8,dO 

• ★ 
r 

was it an end marker? 

bge 

subdiren 

• ★ 
r 

if so, then end 

bra 

subdirl 

• ★ 
r 

else read second 


288 




Abacus 


Atari ST Disk Drives Inside and Out 


subdiren: bra stclstO 


;* to loop 


subdierr: move.w 
jsr 
bra 


dO, — (a7) 
errhand 
stclendl 


;* handle error, error number 


;* Display a page of directory entries * 


showdir: 


showdl: 


showd2: 


move.w 

#0,eflag 



jsr 

cursbuf 

• ★ 
f 

pos. cursos 

jsr 

clrest 

• * 
r 

clear rest of screen 

move.1 

topptr,a5 

• ★ 
r 

pointer in dir buffer 

move.w 

lincount,d7 

• * 
t 

number of lines per page 

move.b 

#' ■ ,d0 

• ★ 
r 

first output spaces 

move.w 

dO, -(a7) 



jsr 

conout 



move.b 

#' 1 ,dO 



move.w 

dO, -(a7) 



jsr 

conout 



clr .1 

d4 



move.w 

#9,d6 

• •k 
r 

length of filename with extension 

move.b 

0(a5,d4.1),dO 

• * 
r 

test if empty dir entry 

beq 

showdien 

• ★ 
r 

if so, then end 

addq.1 

#1, d4 

• ★ 
r 

if not, then 

move.w 

dO,-<a7) 



jsr 

conout 



move.b 

0 (a5, d4.1) , dO 

• ★ 
t 

output filename with ext. 

addq.1 

#1, d4 



move.w 

dO,-(a7) 



jsr 

conout 



dbra 

d6, showd2 



move.w 

#20,tabl 



jsr 

curstab 

• * 

/ 

output file attribute 

jsr 

disattr 



move.w 

#40,tabl 



jsr 

curstab 



jsr 

disclus 

. * 

output start cluster 

move. w 

#55,tabl 



jsr 

curstab 



jsr 

dissize 

• ★ 
f 

and file size in bytes 

move. w 

#0,column 



addq.w 

#1,line 



jsr 

loccurs 



add. 1 

#32,a5 

• ★ 
r 

32 bytes per dir entry 

dbra 

d7,showdl 




289 




Abacus 


Atari ST Disk Drives Inside and Out 


showd8: move.w #0,column ;* output message in last line 

move.w #24,line ; * and 

jsr loccurs 

move.l #sclfrag2,a0 
jsr printf 

rts ;* return 


showdien: move.w #l,eflag 
bra showd8 

.*********************************************************************** 

r 

;* Output a directory line on the screen 

.*********************************************************************** 

r 


dirline: move.l topptr,a3 
move.w #0,eflag 

move.w line,d3 

sub.w #4,d3 

ext.l d3 

lsl.l #5,d3 

move.b #' 1 ,d4 

move.w d4,-(a7) 

jsr conout 

move.w d4,-(a7) 

jsr conout 

move.b 0(a3,d3.1),dO 

beq dirlendl 

move.w d0,-(a7) 

jsr conout 

addq.l #l,d3 

move.w #9,d6 

dirlinl: move.b 0(a3,d3.1),dO 

addq.l #l,d3 

move.w d0,-(a7) 

jsr conout 

dbra d6,dirlinl 

move.w #20,tabl 

jsr curstab 

jsr disattr 

move.w #40,tabl 

jsr curstab 

jsr disclus 

move.w #55,tabl 

jsr curstab 

jsr dissize 

dirlend: rts 


;* pointer in dir buffer 

;* offset from top of screen 
;* times 32, corresponds to 1 dir 
;* two spaces 

;* first byte of the entry, if 
;* zero, then empty entry 
;* else output byte 

;* remaining length of entry 
;* get remaining bytes of entry 

;* and output 


;* output file attribute 

;* and the start cluster 

;* finally file size in bytes 
;* and return 


entry 


290 




Abacus 


Atari ST Disk Drives Inside and Out 


dirlendl: move.w #l,eflag 
bra dirlend 

• ★★★★★★★★★★★★★★★★★★★★★★it**********************************************'** 
/ 

;* Output the number of the first cluster of the current dir entry. * 

• ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★■A’**'***************** 


move . b 

4t= 

a 

o 



move.w 

dO, - (a7) 



jsr 

conout 

• ★ 
t 

output space 

move.w 

line,dO 



sub .w 

#4, dO 



ext. 1 

dO 



lsl.l 

#5,dO 

• * 
r 

times 32 

move.b 

27 <a3,dO.1), dl 

• ★ 
r 

access start cluster in entry 

lsl .w 

#8, dl 

• * 
r 

times 256 because high byte 

move.b 

26(a3 , dO . 1) , dl 

• ★ 

load low byte 

move . w 

dl , clstnum 

• ★ 
r 

store as cluster number 

move.w 

dl, - (a7) 



jsr 

dezpr 

• ★ 

output as decimal number 

move.b 

4t= 

a 

o 

• ★ 
t 

another space and 

move . w 

dO, - (a7) 



jsr 

conout 



rts 


• * 

/ 

return 


* Output the file size of the current dir entry in bytes * 


move.w 

line,d3 




sub .w 

#4,d3 

• ★ 
t 

subtract offset from 

ext. 1 

d3 

• * 

top of screen 

lsl.l 

#5,d3 

• ★ 
t 

times 32 

clr.l 

dl 




move.1 

topptr,a3 




move.b 

31(a3,d3.1), dl 


★ 

most significant byte first (Intel) 

lsl.l 

#8, dl 


★ 

shift byte to next byte pos 

move. b 

30(a3,d3.1),dl 


★ 

load next signif. byte 

lsl.l 

#8, dl 


★ 

and shift another byte pos 

move. b 

29(a3,d3.1) , dl 


* 

to the left 

lsl.l 

=#= 

00 

a 

M 


* 

until all four bytes have been 

move.b 

28(a3,d3.1) , dl 


★ 

read and converted 

move.1 

dl, -(a7) 


■k 

to Motorola format 

jsr 

dezlpr 


* 

then output size in decimal 

move.w 

#$20,-<a7) 


* 

followed by a space 

jsr 

conout 




rts 



★ 

and return 


291 







Abacus 


Atari ST Disk Drives Inside and Out 


* Output the file attribute of the current directory entry. * 


disattr: 

move.w 

line,d3 


sub .w 

#4,d3 


ext. 1 

d3 


lsl.l 

#5,d3 


move.1 

topptr,a3 


move.b 

0(a3, d3.1),dl 


cmp .b 

#$e5,dl 


beq 

deleted 


move.b 

11(a3,d3.1), dl 


cmp.b 

#$10,dl 


beq 

folder 


cmp.b 

#$01,dl 


beq 

readonly 


cmp.b 

#$02,dl 


beq 

hidden 


cmp.b 

#$08,dl 


beq 

disname 


move.1 

#treadwr,aO 


jsr 

printf 

disatten: 

: rts 


disname: 

move.1 

#tdisname,aO 


jsr 

printf 


bra 

disatten 

folder: 

move.1 

#tfolder,aO 


jsr 

printf 


bra 

disatten 

readonly 

: move.1 

#treadon,aO 


jsr 

printf 


bra 

disatten 

hidden: 

move.1 

#thidden,aO 


jsr 

printf 


bra 

disatten 

deleted: 

move.1 

#tdelet,aO 


jsr 

printf 


bra 

disatten 


end 



;* current line 

;* offset to top of screen 

;* times 32 

;* pointer in dir buffer 

;* get first byte of the entry 

;* is it the character for a deleted 

;* file? if so, then display 

;* else get file attribute 

;* is it a subdirectory? if so, 

;* then output 'Subdirectory' 

;* read only? 

; * is it a hidden 
;* file? 

;* is it the disk name 

;* default: file can be read 
;* and written 
;* and return 

;* output and 

;* return 

;* output and 

;* return 

;* output and 

;* return 

;* output and 

;* return 

;* output and 

;* return 


292 




Abacus 


Atari ST Disk Drives Inside and Out 


And finally, the listing of the Format and Gap menu subroutines. 

.******★*******************★******************************************** 

r 

;* Format subroutines * 

;* These routines access subroutines of the TRACK with SYNCS option, * 
;* so that option must be implemented first. * 

.*********************************************************************** 


formatl: 


doforml: 


jsr 

cursmess ; 

* position cursor in message line 

jsr 

delline ; 

* delete line 

jsr 

emptybuf ; 

* and delete cursor buffer 

move. 1 

#fofrag2,a0 ; 

1 * ask for confirmation 

jsr 

printf 


move.w 

wtrack,-(a7) 


jsr 

dezpr 


move.1 

#fofrag5,aO 


jsr 

printf 


move.w 

wside,-(a7) 


jsr 

dezpr 


move.1 

#fofrag6,aO 


jsr 

printf 


move.w 

wdrive,-(a7) 


jsr 

dezpr 


move.1 

#fofrag3,aO 


jsr 

printf 


jsr 

wkey ; 

* read keyboard 

cmp .b 

# 1 y',dO 


beq 

doforml 


cmp .b 

#'Y',dO 


beq 

doforml 


jsr 

delline 

;* if neither upper nor lowercase 'y’ , 

jsr 

emptybuf 

;* then don't format 

move.1 

#fofrag4,aO 


jsr 

printf 


jsr 

wkey 

;* wait for key and 

bra 

formlend 

;* return 

move.w 

#$e5e5, — (a 7) 

;* else format, virgin value 

move. 1 

#$87654321,-(a7 

) ;* magic number 

move.w 

#1,—(a7) 

;* sector interleave 

move.w 

wside,-(a7) 

;* current side 

move.w 

wtrack, — (a 7) 

;* current track 

move. w 

asector,-(a7) 

;* current number of sectors/track 

move. w 

wdrive,-(a7) 

;* current drive 

clr. 1 

— (a 7) 

;* dummy long word 

move. 1 

#formbuf,-(a7) 

;* space for creating track 

move. w 

#10,-<a7) 

;* XBIOS Flopfmt 


293 



Abacus 


Atari ST Disk Drives Inside and Out 



trap 

#14 

;* XBIOS Trap 


add. 1 

#26, a7 



tst .w 

dO 



bmi 

formlerr 

;* error occurred? 

formlend; 

: jsr 

cursmess 



jsr 

delline 



jsr 

cursmess 



move.1 

#fofragl,aO 

;* output message 


jsr 

printf 



jsr 

curright 

;* correct menu cursor, display 


rts 


;* menu and return 

formlerr: 

: move.w 

dO, -(a7) 

;* error number on stack, handle 


jsr 

errhand 



bra 

formlend 

;* and return 

.★★★★★★★★★★★★★★A*****************************************************- 

;* Create a track at the address formbuf with all syncs, which is 

;* then written 

to the disk with the controller write-track command 

; * for 

the purpose of formatting. (xformat in menu) 

.********************************************************************, 

maketr: 

move.w 

#1,sektor 

;* first sector is number 1 


move.1 

#formbuf,a2 

;* address of the track buffer 


move.w 

gapl,dO 

;* first gap 


move.w 

#$4e,d7 

;* header byte is $4E 


jsr 

wbuf f 

;* create gapl in buffer 

maktl: 

move.w 

gap2,dO 

;* number of bytes in 2nd gap 


move.w 

#0, d7 

;* byte value is 0 


jsr 

wbuf f 

;* enter in buffer 


move.w 

#3, dO 

;* three $F5 in buffer as sync byte 


move.b 

#$f5,d7 

;* and to clear CRC register 


jsr 

wbuf f 

;* (checksum), enter in buffer 


move.b 

#$fe,(a2)+ 

;* address mark directly in buffer 


move.w 

wtrack,dO 



move.b 

dO, <a2)+ 

;* current track 


move.w 

wside,dO 



move.b 

dO,(a2)+ 

;* current side 


move.w 

sektor, dO 



move.b 

dO, <a2)+ 

;* current sector 


move.w 

drbyte,dO 

;* number of bytes/sector 


cmp. w 

#1024,dO 



beq 

makt2 



cmp. w 

#512,dO 

;* compare with four possible 


beq 

makt3 

;* values, and then enter 


cmp. w 

#256,dO 



beq 

makt4 



294 


Abacus 


Atari ST Disk Drives Inside and Out 



move . w 

#0, dl 




bra 

makt5 



makt4: 

move . w 

#1 , dl 




bra 

makt5 



makt3: 

move . w 

#2, dl 




bra 

makt5 



makt2: 

move . w 

#3, dl 



makt5: 

move .b 

dl, (a2) + 

• ★ 
f 

required value 


move. b 

#$f7, (a2) + 

• ★ 
t 

checksum of address field in buffer 


move. w 

gap3,dO 

• ★ 
t 

number of bytes in gap 3 


move . w 

#$4e,d7 

• ★ 
r 

filler byte is $4E 


jsr 

wbuf f 

• ★ 
r 

write in buffer 


move . w 

gap2,dO 

• * 

/ 

write gap2 zeros 


move . w 

#0, d7 

• ★ 
t 

in buffer again 


jsr 

wbuf f 




move . w 

#3, dO 

• ★ 
r 

3 sync bytes, written as $A1 


move . w 

#$f5 , d7 

• * 

on the disk, written 


jsr 

wbuf f 

• * 
r 

as $F5 in the buffer 


move . b 

#$fb,(a2)+ 

• * 
t 

data address mark 


move . w 

drbyte,d0 

• ★ 
f 

number of bytes/sector as counter 


move . b 

#$e5,d7 

• ★ 
r 

for data bytes in this sector 


jsr 

wbuf f 

• ★ 
r 

writre $E5 as data byte 


move.b 

#$f7,(a2)+ 

• * 
r 

write checksum 


move.w 

gap4,dO 

• * 
r 

gap5-many $4Es as fill byte for gap4 


move.w 

#$4e,d7 




jsr 

wbuf f 

• * 
r 

write in buffer 


move.w 

sektor,dO 

• ★ 
r 

increment current sector by one 


addq.w 

#1, dO 




move.w 

dO,sektor 




cmp .w 

asector,dO 

• ★ 

/ 

compare number of sectors per track 


ble 

maktl 

• ★ 
r 

with one; if greater, then 


move.w 

gap5,dO 

• * 
t 

last is written to buffer 


move.w 

#$4e,d7 

• * 
t 

and 5th gap at end of track 


jsr 

wbuf f 

• ★ 
r 

can be filled with $4E 


rts 


• ★ 
t 

then return 


.*********************************************************************** 

f 

;* Write the byte value in register D7, DO-times in the buffer 

;* addressed by address register A2. 

.*********************************************************************** 

r 


wbuff: 

subq.w 

#1, dO 

;* adapt counter 

wbuff1: 

move.b 

d7,(a2)+ 

;* write in buffer 


dbra 

dO,wbuff1 

;* DO times 


rts 




295 




Abacus 


Atari ST Disk Drives Inside and Out 






* Pass the address of the track 

* Routine must be called in the 


***************************** 

setbuf: move.l 

#formbuf,dO 

move.b 

dO,dmalow 

lsr. 1 

#8,dO 

move. b 

dO,dmamid 

lsr .1 

#8,dO 

move. b 

dO,dmahigh 

rts 



buffer to the DMA controller. * 

supervisor mode. * 

*************************************** 

;* address of the track buffer 

;* enter low byte 

;* shift 8 bits right 

;* and enter next byte 

;* shift 8 bits right 

;* and enter high byte 


*********************************************************************** 

* Format a track by writing contents of track buffer (in formbuf) * 

* directly to the disk with the write-track command. * 

*********************************************************************** 


xfortrac: 

move.w 

#$190,dmamode 

• ★ 
r 

clear DMA and set to write 


move.w 

#$90,dmamode 

• * 
r 

switch 


move.w 

#$190,dmamode 




move.w 

#$lf,d6 

• ★ 
f 

enter 31 in sector count regi: 


jsr 

wrcontr 




move.w 

#$180,dmamode 

• ★ 

/ 

select FDC register 


move.w 

#$f8,d6 

• ★ 
r 

write-track command 


jsr 

wrcontr 




move.1 

#$60000,d7 

• -k 

t 

timeout counter 

xfortl: 

subq.1 

#1, d7 

• ★ 
t 

decrement 


beq 

xforterr 

• ★ 
r 

if timeout, then error 


btst 

#5,mfp 

• ★ 
t 

FDC done? 


bne 

xfortl 

• ★ 
r 

no, keep waiting 


rts 


• ★ 
r 

else return 

xforterr: 

: move.w 

#-24,-(a7) 

• ★ 
r 

Put error number on stack and 


jsr 

errhand 

• ★ 
t 

handle it 


rts 


* Call the routine for directly formatting a track * 


xformat: 


movem.1 

a3-a6/d3-d7, 

— (a 7) 

jsr 

cursmess 


jsr 

delline 

. * 
f 

move. 1 

#xffragl,aO 

• ★ 
r 

jsr 

printf 


jsr 

emptybuf 

• ★ 

jsr 

wkey 

• ★ 
r 


save registers and output 
message 

empty keyboard buffer 
and wait for keypress 


296 





Abacus 


Atari ST Disk Drives Inside and Out 


cmp .b 

#'y',dO 

beq 

xformit 

cmp .b 

# ' Y 1 , dO 

bne 

xformend 


;* not a 'y' 


xformit: jsr 
st 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 
jsr 

move.1 

jsr 

jsr 

jsr 

sf 

jsr 

jsr 


super 

flock 

setspace 

seldrive 

flreset 

searcht 

rdstrack 

setbuf 

maketr 

searcht 

xfortrac 

emptybuf 

cursmess 

delline 

flreset 

user 

#xffrag2,aO 

printf 

wkey 

super 

flock 

deselect 

user 


* else supervisor on 

* disable floppy interrupt 

* read the track once, 

* accelerates the disk 

* otherwise speed 

* of the inner tracks 

* is not sufficient 

* send track buffer to DMAC 

* create current track in buffer 

* and find track 

* write track on disk 


;* reset controller 
;* enable user mode again 

;* output message 
;* read keyboard 
;* enable supervisor 
;* release floppy interrupt 
;* deselect drive 
;* switch to user mode 


xformend: jsr 
jsr 
jsr 

move.1 
jsr 

movem.1 
rts 


cursmess 

delline ;* output message, restore 

cursmess ;* registers, and 

#drfragl,aO 
printf 

(a 7)+,a3-a6/d3-d7 

;* return 


*********************************************************************** 

* The following menu options increment and decrement the gaps in the * 

* menu. See the sector menu for details. 
*********************************************************************** 


incgaps: cmp.w 
bit 

move,w 
bra 

incgapsl: addq.w 


#99,dO 
incgapsl 
#0, dO 
incgaps2 
#1, dO 


;* maximum number of fill bytes for all 
;* gaps is 99, this routine is called 
;* by all incgap menu options 
;* because the limits 
;* are the same 


297 




Abacus 


Atari ST Disk Drives Inside and Out 


incgaps2: rts 


incgapl: move.w 

gapl,dO 

jsr 

incgaps 

move. w 

dO, gapl 

divu 

#10,dO 

add.b 

#'0',dO 

move.b 

dO, mgapl 

swap 

dO 

add.b 

# ' 0 ', dO 

move. b 

dO,mgapl+1 

jsr 

dispmen 

rts 


incgap2: move.w 

gap2,dO 

jsr 

incgaps 

move.w 

dO,gap2 

divu 

#10,dO 

add.b 

#' 0 ', dO 

move.b 

dO,mgap2 

swap 

dO 

add.b 

# 1 0 ', dO 

move.b 

dO,mgap2+l 

jsr 

dispmen 

rts 


incgap3: move.w 

gap3,dO 

jsr 

incgaps 

move.w 

dO,gap3 

divu 

#10,dO 

add.b 

o 

o 

move.b 

dO,mgap3 

swap 

dO 

add.b 

#'0',dO 

move.b 

dO,mgap3+l 

jsr 

dispmen 

rts 


incgap4: move.w 

gap4,dO 

jsr 

incgaps 

move.w 

dO,gap4 

divu 

#10,dO 

add.b 

O 

a 

o 

move. b 

dO,mgap4 

swap 

dO 

add.b 

o 

a 

o 

move. b 

dO,mgap4+l 


298 


Abacus 


Atari ST Disk Drives Inside and Out 


jsr dispmen 

rts 


incgap5: move.w 

#-l,-(a7) 

move.w 

#11,-(a7) 

trap 

#13 

addq.1 

#4,a7 

move.w 

#10,dl 

btst 

#0, dO 

bne 

incgap5x 

btst 

#1, dO 

bne 

incgap5x 

move.w 

#1, dl 

incgap5x: move.w 

gap5,dO 

add.w 

dl, dO 

cmp .w 

#999,dO 

ble 

incgap5a 

move.w 

#0, dO 

incgap5a: move.w 

dO,gap5 

ext. 1 

dO 

divs 

#100,dO 

add.b 

#•0',d0 

move .b 

dO,mgap5 

swap 

dO 

ext. 1 

dO 

divs 

#10,dO 

add.b 

=#= 

o 

a 

o 

move. b 

dO,mgap5+l 

swap 

dO 

add.b 

o 

a 

o 

move. b 

dO,mgap5+2 

jsr 

dispmen 

rts 

decgaps: cmp.w 

#0, dO 

ble 

decgapsl 

subq.w 

#1, dO 

bra 

decgaps2 

decgapsl: move.w 

#99,dO 

decgaps2: rts 

decgapl: move.w 

gapl,dO 

jsr 

decgaps 

move.w 

dO,gapl 

divu 

#10,dO 

add.b 

#'0',dO 

move.b 

d0,mgapl 


;* shift pressed? 


called from all decgap menu 
because max and min are the 
same for all gaps 


options 


299 



Abacus 


Atari ST Disk Drives Inside and Out 


decgap2: 


decgap3: 


swap 

dO 

add.b 

#'0 1 ,dO 

move.b 

dO,mgapl+1 

jsr 

dispmen 

rts 


move.w 

gap2,d0 

jsr 

decgaps 

move.w 

dO,gap2 

divu 

#10,dO 

add.b 

#'0 1 ,dO 

move. b 

dO,mgap2 

swap 

dO 

add.b 

# ■ 0',d0 

move. b 

dO,mgap2+l 

jsr 

dispmen 

rts 


move.w 

gap3,dO 

jsr 

decgaps 

move. w 

dO,gap3 

divu 

#10,dO 

add.b 

# 1 0',dO 

move. b 

dO,mgap3 

swap 

dO 

add.b 

=#= 

O 

a 

o 

move. b 

d0,mgap3+l 

jsr 

dispmen 

rts 



decgap4: 


decgap5: 


move.w 

gap4,dO 

jsr 

decgaps 

move.w 

dO,gap4 

divu 

#10,dO 

add.b 

O 

a 

o 

move.b 

dO,mgap4 

swap 

dO 

add.b 

# ’ 0■,d0 

move. b 

dO,mgap4+l 

jsr 

dispmen 

rts 


move.w 

#-l,-(a7) 

move. w 

#11,-(a?) 

trap 

#13 

addq.1 

#4,a7 

move.w 

#10,dl 


300 


Abacus 


Atari ST Disk Drives Inside and Out 


btst #0,d0 

bne decgap5x 

btst #l,dO ;* right shift key 

bne decgap5x 

move.w #l,dl 

decgap5x: move.w gap5,d0 
sub.w dl,d0 

bpl decgap5a 

move.w #999,dO 


decgap5a: move.w d0,gap5 


ext. 1 

dO 

divs 

#100,dO 

add.b 

# 1 0 1 ,dO 

move. b 

dO,mgap5 

swap 

dO 

ext .1 

dO 

divs 

#10,dO 

add.b 

#•0■,d0 

move.b 

dO,mgap5+l 

swap 

dO 

add.b 

=H= 

O 

a 

o 

move.b 

d0,mgap5+2 

jsr 

dispmen 

rts 








* Change number of bytes per sector, stored in drbyte and affect 

* the number of displayed and written bytes in the sector menu. 


* though only if 


format module is included. 

***************************************************** 


* 

* 

* 

* 


incbyte: move.w 
cmp .w 
beq 
cmp.w 
beq 
cmp.w 
beq 
move.w 
move.b 
move.b 
move.b 
move.b 
bra 


drbyte,dO ;* possible number of bytes/sector 

#128,dO ;* is 128, 256, 512, or 1024 bytes 

incbyl 

#256,dO 

incby2 

#512,dO 

incby3 

#128,dO 

#'0',mdrisect ;* enter in menu text 
# 1 1 1 ,mdrisect+1 
#'2',mdrisect+2 
# 1 8 1 ,mdrisect+3 
incbywei 


301 


Abacus 


incbyl: move.w 
move.b 
move.b 
move.b 
move.b 
bra 

incby2: move.w 

move.b 
move.b 
move.b 
move.b 

bra 

incby3: move.w 
move.b 
move.b 
move.b 
move.b 

incbywei: move.w 
jsr 
rts 


#256 

;,do 

# ■ 0 ■ 

,mdrisect 

#'2 ■ 

,mdrisect+1 

#' 5 ' 

,mdrisect+2 

#'6' 

,mdrisect+3 

incbywei 

#512 

, dO 

#' 0 • 

,mdrisect 

#'5' 

,mdrisect+1 

# • 1 • 

,mdrisect+2 

#'2 ' 

,mdrisect+3 

incbywei 
#1024,dO 

#’ 1 ■ 

, mdrisect 

#'0’ 

, mdrisect+1 

#'2 ' 

, mdrisect+2 

#'4 ' 

, mdrisect+3 

dO,drbyte 
dispmen 


Atari ST Disk Drives Inside and Out 


.*********************************************************************** 
;* Decrements number of bytes/sector, like incbyte, only allows the * 
;* four possible FDC values (128, 256, 512, 1024) . * 

;*********************************************************************** 


decbyte: move.w 
cmp .w 
beq 
cmp.w 
beq 
cmp. w 
beq 
move.w 
move.b 
move.b 
move.b 
move.b 
bra 

decbyl: move.w 
move.b 
move.b 
move. b 


drbyte,d0 

#128,dO 

decbyl 

#256,dO 

decby2 

#512,dO 

decby3 

#512,dO 

#'0',mdrisect 

#'5',mdrisect+1 

#'1',mdrisect+2 

# 1 2',mdrisect+3 

decbywei 

#1024,dO 
#'1',mdrisect 
# 1 0',mdrisect+1 
# 1 2',mdrisect+2 


302 


Abacus 


Atari ST Disk Drives Inside and Out 


move. b 
bra 

decby2: move.w 

move.b 
move.b 
move.b 
move.b 
bra 

decby3: move.w 

move.b 
move.b 
move.b 
move.b 


#'4',mdrisect+3 
decbywei 

#128,dO 
#'0',mdrisect 
#'1',mdrisect+1 
#'2',mdrisect+2 
#'8 1 ,mdrisect+3 
decbywei 

#256,dO 
# 1 0',mdrisect 
# 1 2',mdrisect+1 
#'5 1 ,mdrisect+2 
# ' 6',mdrisect+3 


decbywei: move.w dO,drbyte 
jsr dispmen 

rts 

end 


Operating the disk editor 

The disk editor is primarily controlled with the cursor keys: Cursor left and 
cursor right move you through the different menu selections; cursor up and 
cursor down select the menu point, or change the variable section of a menu 
point (drive, side, track, etc.). Most menu point selections will bring you 
into a new menu, from which you select a new menu point. 

The next section lists the definition of each menu point 


7.2.1 The main menu 


All points in this menu except END take you to a new menu: 

TRACK: Takes you to the TRACK menu, in which entire 

tracks can be handled. 

TRACK/SYNC: Selects the TRACK WITH SYNC BYTES menu; 

this mode allows you to access all information on 
the diskette, such as gap and synchronization bytes. 


303 



Abacus 


Atari ST Disk Drives Inside and Out 


SECTOR: 

CLUSTER: 

FORMAT: 

OPTIONS: 

END: 

7.2.2 The 

drive: 

side 0: 
track 00: 

sect/trac 00: 

READ: 

WRITE: 


Selects SECTOR mode, which allows reading, 
editing and writing sectors. 

Selects CLUSTER mode, from which diskette 
clusters can be accessed. 

Selects FORMAT mode. From this mode you can 
format individual tracks with different formats 
(including non-Atari formats). 

Selects OPTIONS menu. You can declare the 
current drive, and determine the maximum number 
of tracks and sectors. 

End program, return to Desktop. 


TRACK menu 


0 is default, and the cursor up and cursor down 
keys let you select a new drive. All menu points 
followed by a colon and a number have this option 
of selecting another number with the cursor keys. 

Selects the disk side, either 0 or 1. 

Selects the track to be accessed. The maximum 
selectable number will be selected in the OPTIONS 
menu from the main menu. 

Sets the number of sectors per track to be read from 
and written to. 

Selecting this point will read the presently listed 
track from diskette, and display it. Cursor up and 
cursor down scroll you through the individual 
sectors. It is also possible to call the EDIT function 
with cursor left and cursor right, which lets you 
change the tracks as you scroll through the text. 

Following a confirming prompt, the entire track 
will be rewritten to diskette. 


304 


Abacus 


Atari ST Disk Drives Inside and Out 


EDIT: Provides editing for a sector of a track. It can also 

be called from the READ function, but then you can 
only edit one sector of a track. 

BACK: Exit to main menu. 


7.2.3 The TRACK with SYNC menu 


drive 0: Selects the current disk drive 

side 0: Selects the current side 


track 00: Selects the current track 

readwithsync: Reads the entire track with all gaps and enables 

scrolling through the entire track 

Addrfield: Shows the address field of an entire track with byte 

size and checksum. Output is doubled, so that 16 
address fields are always displayed 


BACK: Exit to main menu 


7.2.4 The SECTOR menu 


drive 0: 
side 0: 
track 00: 
sector 00: 
READ: 
WRITE: 


Selects the current drive 

Selects the current side 

Selects the current track 

Selects the current sector 

Reads and displays the current sector 

Writes the sector currently in memory to diskette, 
following a confirming prompt 


305 


Abacus 


Atari ST Disk Drives Inside and Out 


EDIT: Branches to EDIT mode, which allows hexadecimal 

input and access to all sector bytes using the cursor 
keys. Pressing <Retum> exits the EDIT mode. 

BACK: Exit to main menu 


7.2.5 The CLUSTER menu 


drive 0: Selects the current drive 


clust 0000: 


READ: 


WRITE: 


EDIT: 


Selects the current cluster; increases and decreases 
the cluster number by pressing cursor up or cursor 
down (<Shift> cursor up or <Shift> cursor down 
increases or decreases the cluster number by 10). 

Reads the current cluster in memory, and computes 
the physical sector, next to track and side, at which 
this cluster begins. The information regarding the 
physical sector will be taken over to the sector 
menu, i.e., when you go to the SECTOR menu 
after reading a cluster, you can immediately read the 
start sector through READ. 

Writes the cluster found in memory to the cluster on 
diskette displayed on the menu, following a 
confirmation prompt. 

Allows cluster editing. Pressing <Return> ends 
EDIT mode. 


Startoffile: 


BACK: 


Displays all files on the current drive with identical 
file attributes. Scrolling through the individual files 
in made possible by the cursor up and cursor down 
keys; pressing <Retum> brings the start cluster of 
the currently selected file into the CLUSTER menu. 
If the selected file represents a subdirectory, then 
the system will branch and allow you to select from 
a subdirectory. Returning to the root directory 
allows selection of individual points. 

Exits to main menu 


306 


Abacus 


Atari ST Disk Drives Inside and Out 


7.2.6 The 

drive 0: 
side 0: 
track 00: 
sec/tra.00: 

FORMAT: 

XFORMAT: 

GAPS: 

BACK: 

7.2.7 The 

GAPl 00: 

GAP2 00: 
GAP3 00: 
GAP4 00: 


FORMAT menu 


Selects the current drive 
Selects the current side 
Selects the current track 

Select sectors per track. The maximum possible 
number depends on the menu point MAXSECT 
chosen from the OPTIONS menu; i.e., if there is a 
10 in MAXSECT, you may select 10 sectors per 
track. 

Formats the current track with sec/track sectors, 
preceded by a confirmation. Formatting follows 
from the XBIOS function, and formats basic 
sectors with 512 bytes (Atari format). 

Formats the current track with the parameters 
changed in the GAP menu; you may set the number 
of bytes per sector as well as the number of 
synchronization bytes. 

Branches to its own menu, in which the parameters 
can be stated for XFORMAT. 

Exit to main menu 


GAP menu 

Determines the number of fill bytes at the start of 
track; maximum is 99. 

Determines the number of null bytes 

Determines the number of null byte 

Determines the number of null bytes 


307 





Abacus 


Atari ST Disk Drives Inside and Out 


GAP5 00: Determines the number of fill bytes that will be 

inserted at the end of the track. 

BYT/SEC: Here one of the four byte per sector formats 

supported by the disk controller can be selected 
(128, 256, 512, 1024). The choice influences 
sector reading in the SECTOR menu, so that 
1024-byte sectors must also be taken on when 
editing, etc. 

BACK: Exit to main menu 


7.2.8 The OPTIONS menu 


drive 0: Selects current drive 

MAXTRACKOO: Selects maximum selectable tracks for the TRACK 
menu 

MAXSECT 00: Selects the maximum selectable sectors for the 
SECTOR menu point, and states the maximum 
number of sectors per track 

EMIT DRIVE: Calls the BIOS function and displays disk 

parameters 

SHOW BPB: Displays the BIOS parameter block of the current 

drive 

BACK: Exit to main menu 


308 




Abacus 


Atari ST Disk Drives Inside and Out 


7.3 Sample use of the disk editor 


First we'll look at a disk directory, then the File Allocation Table (FAT). To 
do this, format a single-sided disk named WORK.TST, and copy the 
EMULATOR. ACC program to this disk from the system disk. 

As we've seen above, GEMDOS divides diskettes into clusters (blocks) of 
two sectors with 512 bytes apiece, or a total of 1024 bytes. Six times 1024 
is 6144, so EMULATOR. ACC fits into 7 clusters rather than 6. Now load the 
disk editor, select the SECTOR menu and select drive number 0, track 1, 
side 0 and sector 3. This is where the first file results on a single-sided 
diskette. The <p> key will print out the sector. 

Now we see the results of our efforts. First you'll see the name given the 
disk after formatting. Every directory entry, including the disk name, takes 
up 32 bytes. The disk name requires bytes 0 to 31 of the sector, and the first 
directory entry begins at byte 32 ($20 hexadecimal). The first 11 bytes (0 to 
10) or every directory entry are reserved for the filenames, and spaces (hex 
$20) are inserted at any of the eight filename characters that are unoccupied. 
The next three bytes (8-10) are set aside for the file extension. 

All data which now follows will be on the diskette in Intel format, i.e., any 
data of more than one byte will be stored as low byte and high byte. 
Therefore, the data word $1234 will be stored as $34 $12. 

The twelfth byte (11) of every entry functions as a data attribute, and 
identifies the different access options of the file. The number $08 in the data 
attribute field of the disk name identifies this entry as the disk name. 

11 bytes follow which serve no purpose (12 to 21, $0C-$15), but in bytes 
22 and 23 ($16 and $17), the time of the last write access to the file stands 
relative to the beginning of the entry. The time is coded in the bits of these 
two bytes, as you have already seen in Chapter 3.3. One item of note is that 
the seconds are counted in 2-second-click increments, so that the second 
must be multiplied by 2 to arrive at the proper time. 

In conclusion, the time bytes are followed in the directory entry by the date 
bytes (24-25, $18 $19), which are coded in a similar manner. 

The two most important bytes of any directory entry are bytes 26 and 27 
($1A, $ IB) relative to the beginning of the entry; this is where the starting 


309 




Abacus 


Atari ST Disk Drives Inside and Out 


cluster of the file is given. As you can see for yourself, our file lists $02 
$00, which gives us the start cluster of $0002. The file EMULATOR. ACC, 
therefore, starts at cluster number 2, which is also the first free cluster that 
the operating system finds on a diskette. To convert the cluster number into 
the logical and physical sector number, some of the parameters of the BIOS 
parameter blocks and of the boot sector will be given (clsize, datrec, spt, 
nside). The conversion appears as follows: 

1. Subtraction from the cluster number by 2, as cluster 
number 2 is numerically the first free cluster of the 
operating system. 

2. Multiplication of the above result by the number of 
sectors per cluster (clsize = 2 in Atari ST). 

3. Addition of the number of the first logical data sector 
(datrec = 18 in Atari ST). 

The resultant number represents the logical sector number of the first sector 
of this cluster. The second sector of the cluster directly follows (single¬ 
sided diskettes). Double-sided diskettes have the first sector of the first data 
cluster at side 0, track 1, sector 1; the second sector of this cluster at side 0, 
track 1, sector 2. The cluster in this case will have the sectors to follow set 
on a track. When the last sector of a track on side 0 is reached, the operating 
system writes the next sector on the same track, sector 1 of side 1. If Atari 
formatting has been done with 9 sectors, the first physical sector of the fifth 
data cluster will be written to side 0, track 1, sector 9, and the second sector 
of this fifth data cluster will be on side 1, track 1, sector 1. 

But we digress—back to the logical sector of the start cluster. It's still 
missing the computation of the physical track and sector, on which this 
logical sector (which numerically starts with 0) is found. Let's take a 
single-sided diskette as a basis, and divide the logical sector number by the 
number of sectors per track (spt = 9, Atari format). The result of the 
division is the track, the remainder of the division the offset by sector 1 of 
this track. 

Look at the first file again: Cluster number 2 minus 2 is 0; multiplied by 2 
sectors per cluster, we still have 0; adding 18 gives us 18; divide this by 9 
sectors per track—the result is 2, remainder 0. The first sector of the first 
cluster of the file EMULATOR. ACC is located on track 2 sector 1. 


310 



Abacus 


Atari ST Disk Drives Inside and Out 


The calculations for finding the logical sector of a double-sided formatted 
disk are the same, only the computation of the physical track and sector 
must take the side into consideration. The logical sector number will again 
be divided by the number of sectors per track (spt), and the remainder of 
this division gives the offset of sector 1, only the computation of the track 
differs a bit. The result of the number of sectors per track will be divided by 
the number of sides, namely, 2 for a double-sided format diskette. If there 
is no remainder from the division, the track of this sector is on side 0. If 
there is a remainder, then the computed track is on side 1 of the diskette. 

Now on to computing the physical sector for cluster 2 of a double-sided 
formatted diskette. There is no change in calculating the logical sector: It is 
also 18 here; divide by the number of sectors per track (9), which gives us 2 
remainder 0. The sector number is 1 (from the null remainder). To establish 
track and side, divide the 2 by the number of sides on the diskette (2), 
which is 1 remainder 0. So, according to the above rules, the sector will be 
found on track 1, side 0 of the diskette. 

For further testing, we will now determine the start sector of the directories 
for single- and double-sided format diskettes. The logical start sector is 
given as BPB and boot sector, in which the product of the number of File 
Allocation Tables (fat = 2) and the number of sectors per File Allocation 
Table (spf = 5) added. Therefore, logical sector =1 + 2*5 = 11. The start 
of directory will be found on all Atari diskettes at logical sector 11. 

For the physical sector of a single-sided diskette: 11/9 (sectors/track) = 1 
remainder 2. 1 + remainder = 3; the logical sector 11 is found on track 1, 
sector 3 of a single-side diskette. 

For a double-sided diskette: 11/9 (sectors/track) = 1 remainder 2. 1 + 
remainder=3 (sector). 1/2 = 0 remainder 1 = side 1; track = result of the 
first division (1). The logical sector 11 is found on side 1, track 0, sector 3 
of a double-side diskette, as you can see for yourself. 

In the process of cluster computation, we've neglected the completion of the 
directory entry for the file EMULATOR. ACC. Out of the 32 bytes per 
directory entry, we have skipped the last 4 bytes (28-31, $1C-$1F), which 
gives the file size in bytes. $32 $19 $00 $00 gives us $00001932 in Intel 
format, and this hexadecimal number is converted by the Desktop into a 
decimal format (6450). Before you can again look into a table, two bytes 
with other functions must be mentioned: They are the first byte of the 
directory entry (byte 0), as well as the twelfth byte (byte 11), the attribute 
byte. 


311 



Abacus 


Atari ST Disk Drives Inside and Out 


The first byte of the name, which in our example is $45, means that after 
bytes unequal to $E5 (or $00), then $2E, the ASCII code of the first 
character follows ($45 = "E"). The remaining entries have the following 
meanings: 

l&t-kYte Me anin g 

$00 This file hasn't been used yet ($E5=this file has been 
used, but it was deleted) 

$2E This byte indicates a path from subdirectory to root 
directory. If the next byte is $2E, the cluster number 
array will contain the cluster number of the next 
directory in line; if the Second byte is $00, the next 
directory in line is the root directory. This will be 
explained in detail below. 

The attribute byte (byte 11) can take on the following values: 

Bvte: Meaning; 

$00 This file can be read from as well as written to. 

$01 This file is read only. 

$02 This file is not displayed in the directory (hidden). 

$08 This identifies a diskette name; all bytes after 10 
have no meaning. 

$10 The filename is handled as a subdirectory (folder). 

The functions of the 32 bytes of every directory entry are: 


Bvte: 

Meaning; 

0-10 

Filename with extension, first byte is status byte 
($E5, $2E) 

11 

File attribute (read/write, read only, subdirectory) 

12-21 

unused 

22-23 

Time 

24-25 

Date 

26-27 

Start cluster of the file 

28-31 

File size in bytes 


312 




Abacus 


Atari ST Disk Drives Inside and Out 


7.3.1 File Allocation Table 


Now you know how to find the beginning of a file on diskette. Bytes 
number 26 and 27 of the directory entry for the file are converted to 
decimal, and the given cluster number is converted to the logical sector 
number, etc., according to the abovementioned rules. But how do we find 
the second cluster of a file, or the last? 

The answers are in the File Allocation Table, whose beginning is always 
found at side 0, track 0, sector 2, of single- and double-sided format disks. 
To understand this better, let's look at sector 2, track 0, side 0 of a 
single-sided diskette (the disk you've been using so far will do) with the 
disk editor. The first three bytes ($F7 $FF $FF) have a structure to them. 

This FAT is where we'll find information about every cluster of the 
diskette, and even whether the disk is readable, and if so, which is the next 
cluster of the file. First, though, let's get away from this odd structure (03 
04 00 05) and use the numerals 3,4,5, etc. Our table looks like this: 

START: 1, 2, 3, 4, 5 

START should only symbolize the address at which the number 1 will be 
found. The entire list is linear; the null list element (relative to START) has a 
value of 1, the first, 2, etc. If we read the address START, we'll find a 
value of 1. This number 1 should indicate the information of the next list 
element to be read. By adding the number 1 to the address of START, and 
read the found address (START+1), we get the result 2. 

We can say this about the 2 after START: The number of the list element to 
be read is at the address START+2, or the number 3. So it is possible to 
jump from list element to list element, by just reading the elements and 
looking for the result of the offset relative to the start of the list. At first 
glance, this looks a little bit like the method used by the operating system to 
find the cluster on diskette. 

Let's look at the rest of our simplified FAT entries (3,4,5) and add two 
additional dummy values (x,x,3,4,5). Our cluster number for 
EMULATOR. ACC is 2, the number for the address START+0 is x, as is the 
reading for the address START+1. But if we read START+2, we get the 
number 3, and reading START+3 gives us 4. This means that on 
EMULATOR . ACC, the next cluster following cluster 2 is number 3, after 
number 3 is 4, etc. 


313 




Abacus 


Atari ST Disk Drives Inside and Out 


The conversion from cluster numbers to sector numbers is already familiar 
to you; we still need a method of finding the end of the file. The solution 
lies in the operating system, with the help of the FAT: By reading a specific 
value in an already read address, the cluster read from it will be the last one 
of the file. 

This may be a little complicated, since Intel format with its 12-bit 
representation is brought into play. A FAT entry consists of 12 bits, with 3 
nibbles of 4 bits. The 12-bit format is perfect, since no more than 2 A 12 = 
4096 clusters are available on diskette. 

To explain the strange format and recognize the cluster number, let's have 
another look at the FAT. First we think about 16 bits per FAT entry, which 
are set up in Intel format. Of these 16 bits, the most significant nibble (the 
first of four bits) of the high byte is unnecessary, and is marked with an X. 
This free nibble will now be set up as the least significant nibble (the last of 
the four bits) of the low byte of the next entry. The most significant nibble 
of the low byte and the least significant nibble of the high byte take a cross 
exchange together in place of the low byte. From two 16-bit entries we get 
two 12-bit entries, from which a nibble is reserved (the high byte of the 
second entry). With a byte reserved per two entries, the entire system is 
periodically symmetrical, i.e., for every two 12-bit entries there is a nibble 
shift, and the whole process begins again. 

To convert 12-bit Intel format entries into readable 12-bit Motorola format 
entries, the number of entries are of different meanings. Begin with the 
number 0 and count three nibbles as one entry. As we did in the simplest 
example above (x,x), the first couple entries (0 and 1) in the real FAT (F7 
FF FF) have no meaning, and the first valid entry to follow is the number 2. 
If the access number is even, as in this case (2), then you'll find the two 
least significant nibbles (Motorola format) in the first byte of this entry (03), 
and the most significant nibble (in Motorola format) of the following cluster 
in the second nibble of the following bytes (0), so that the follow cluster 
number 3 (Motorola format) is conveyed. 

If you want to find the following cluster of this third data cluster, then count 
in groups of three from the beginning and find the bytes 40 00 in the fourth 
entry (number 3), whereby the beginning of the third group proper is the 
zero in the first byte. An odd access number (in this case 3) represents the 
last two nibbles of the second byte (00) of the high nibble and the first 
nibble of the first byte as the least significant nibble of the cluster number. 
In concrete examples, the cluster to follow will be conveyed as the number 
4. 


314 




Abacus 


Atari ST Disk Drives Inside and Out 


7.3.2 Subdirectories and folders on diskette 


The file system of Atari TOS is hierarchal and recursive. That is, you can 
get to any subdirectory (or folder) from the root (main) directory. To get a 
better grasp of this, select the Desktop menu point New Folder . . . and 
create two folders with the names FOLDER1. SUB and FOLDER2 . SUB. 

Now start the disk editor and read the directory sector from the SECTOR 
menu (side 0, track 1, sector 3). At byte number 11 (see above) you'll 
recognize the entry FOLDER1. SUB ($10) as a subdirectory entry. The start 
cluster of this subdirectory is cluster number 9 (bytes 26 and 27) which 
starts at track 3, sector 6 of a single-sided diskette. Read this sector into 
memory using the SECTOR menu. 

Every subdirectory has its own directory sectors through the operating 
system. These subdirectory sectors take up the first couple of entries, even 
if there are no files in the subdirectory. The first entry begins with a period 
($2E) followed by spaces. A $10 stands in the attribute byte as the identifier 
of the subdirectory, and the start cluster is entered as its own beginning, 
which in this case is 9. The second directory entry of a subdirectory, set 
apart by two periods ($2E), has in its start cluster entry (bytes 26 and 27) 
the start cluster of the next deepest subdirectory. In our case, we find two 
null bytes (00 00), which means: The next deepest subdirectory from the 
subdirectory FOLDER1. SUB is the main directory (root directory). 

Exit the disk editor and call a directory from the subdirectory 
FOLDER1 .SUB by double-clicking the name. When the empty folder 
FOLDER 1. SUB is displayed, make another folder called INFOLD 1. SUB 
by clicking the New Folder.... menu point. Now restart the disk 
monitor. The main directory (track 1, sector 3) remains unchanged, so you 
can immediately go to the starting sector of the subdirectory folder 1. 
SUB at track 3, sector 6, with the help of the SECTOR menu. 

Now we can see that there is another folder inside this subdirectory from 
looking at the directory sector of the subdirectory; this folder has the 
number 11 as the start cluster. Cluster number 11 begins on a single-sided 
diskette at track 4, sector 1, which we'll now read. The first entry of the 
subdirectory has the recursive reference to itself and in the second entry, the 
reference to the next deepest subdirectory, which in this case corresponds to 
the subdirectory FOLDER1. SUB, which begins at start cluster 9. 


315 




Abacus 


Atari ST Disk Drives Inside and Out 


7.3.3 Formatting in non-Atari format 


There are two types of non-Atari formats. One consists of the use of more 
tracks and sectors than are formatted by the Desktop (80 tracks 0-79, and 9 
sectors per track 1-9); the other is made up of different numbers of bytes per 
sector and more or fewer synchronization bytes between the address and 
data fields. For example, if you'd like to format 81 tracks with 10 sectors, 
select the OPTIONS menu and raise the variable MAXTRACK to 81 using 
your cursor keys. Use the same procedure in MAXSECTOR to raise that 
number to 10. Now exit the OPTIONS menu by selecting BACK, and 
select the FORMAT menu. Raise the track number to SI and the sector 
number to 10. Finally, select FORMAT, put in a blank disk, and press <y> 
to answer the confirmation: Then you'll get a disk with track 81 formatted to 
10 sectors. 

If you'd like to get away from Atari format and adjust the sectors and sector 
sizes to your own preferences, we must get past the TOS programming and 
directly access the disk controller. Naturally, we must limit ourselves by 
choice to the limits of the disk controller itself. In other words, you can't 
format sectors with 630 bytes per sector, because the disk controller can 
only handle four types of sector sizes (128, 256, 512, 1024). To format 
track 79 with 4 sectors and 1024 bytes per sector, with a track width of 32 
bytes of $4E instead of 60 bytes of $4E, select the menu point FORMAT, 
then the submenu GAPS. You'll get a new menu where you can decrease 
the value of GAP1 to 32, and raise the amount of BYT/SEC to 1024. Once 
you return to the FORMAT menu by selecting BACK, decrease the menu 
point SEC/TRAC to 4 and TRACK to 79. Finally, go to XFORMAT. 

Answer the confirmation with <Y>, and track 79 will be reformatted. You 
should wait a little longer than usual since the disk drive motor runs on. I 
had installed a pause, but in the testing phase a constantly spinning motor is 
useful, especially since different drives have different spin-up times. This 
means that the built-in drive in the 1040ST reaches its spin-up speed faster 
than, e.g., the "old" SF 354, so the program section which directly accesses 
the floppy controller functions differently with different drives (sometimes it 
works, sometimes it doesn't). These errors came up in the testing phase, 
though, and no longer exist. However, if you happen to be working with an 
exotic disk drive (like an old 5 1/4") and the menu points READ with 
SYNCS or XFORMAT don't work, you should get the drive motor running 
by leaving the READ with SYNCS menu early, then call the functions again 
once the motor is running. 


316 




Abacus 


Atari ST Disk Drives Inside and Out 


To test the TRACK with SYNC menu in a practical fashion, take a normal 
formatted diskette, and select this menu point. Then read track 79 by 
choosing READ with SYNCS, and look at the first byte. 

Track span should now be around $4E sixty times from the start of track, 
but it could be another value (e.g., $E4, $9C, $27). This phenomenon will 
be set by the controller if the read procedure isn't synchronized to the start 
of track, so, for example, the first bit from $4E will be read, and the 
controller will read the next 8 data bits as the first byte. 

Example: 

4 E 4 E 4 . . —> 9 C 9 C 9 

0100 1110 0100 1110 0100 1 ..—> 1001 1100 1001 1100 1001 

After the track span of 60 bytes, 12 null bytes follow ($00); the first and last 
null bytes can be cut off and changed to other values. In connection with 
these, the first synchronization bytes appear, namely three sets of $A1, 
whereby the first $A1 is not read correctly. The three $A1 bytes switch on 
the hardware checksum communications, i.e., the disk controller places the 
checksum above the data bytes to follow. The next byte is $FE, which 
identifies the following six data bytes as an address field. The contents of 
these bytes are ($4F, $00, $01, $02, $70, $1D), $4F: Track 79, $00: side 
0, $01: sector 1, $02: the following data sector consists of 512 bytes, $70 
$1D: address field checksum. Next follows $4E twenty-two times, and $00 
twelve times, then $A1 three times. The next byte ($FB) contains 
information about the following 512 data bytes (a freshly formatted diskette 
has all $E5 here), followed by two checksun bytes ($C4 $0B). The end of 
the data sector has $4E written forty times, and then the individual 
synchronization range ($00, $4E, $A1, etc.) is repeated for the eight 
address and data fields of this track to follow. 

Exit the TRACK with SYNC menu and selet the submenu GAP from the 
FORMAT menu. Now increase GAP2 from 12 to 15 with the cursor keys, 
select XFORMAT and confirm the procedure with <Y>. Now when you 
look at the newly formatted track 79 with the TRACK with SYNC menu, 
you'll see $00 fifteen times between the individual address and data fields. 


317 


Abacus 


Atari ST Disk Drives Inside and Out 


7.4 Assembling with different assemblers 

Digital Research: 

1. Comments must be changed to begin with * 

2. Assemble with: as 68 . ttp -1 -u editor, s 

3. Link with: link68 .ttp [u] edit. 68k=edit. o 

4. Make it loadable with: re lmod .ttp edit.68k edit.tos 

The file edit. tos is then loadable through clicking. 

GST Assembler: 

1. opt abs must be inserted at the beginning of the file edit. s and 
all memory directives such as text, bss, data must be execu¬ 
ted through section, text should become section text. The 
program file can be saved after editing with the name edit. gst. 

2. Create a linkfile named asl. Ink, which contains only one line 
saying input *. 

3. Assemble edit. gst with asm.prg edit. gst - errors 

4. Link with link, prg edit -with asl. Ink -prog 
edit.tos 

The file edit. tos is then startable. 

Metacomco Assembler: 

The program file edit. s can be used without alterations. 

1. Make a linkfile called a s 1. Ink which contains one line- 
input * 

2. Assemble with ass em. ttp to edit. s to edit.bin 

3. Link with link . ttp edit.bin -with asl. 

The program edit. prg is startable. 


318 




Chapter Eight 






Abacus 


Atari ST Disk Drives Inside and Out 


Machine language utilities for BASIC 


ST BASIC is equipped with a large number of functions and is also quite 
fast. But problems still arise which either cannot be solved at all in BASIC 
or are very difficult to solve. Time problems also arise when large quantities 
of data must be processed. 

We can get some help from a more or less small machine language program 
which can be incorporated into the BASIC program. Such a subroutine can 
be easily placed in an integer array (such as A% (n) ) and called. Certain 
things must be taken into account when combining BASIC and machine 
language, and we will look at them here. 


8.1 Calling and passing parameters 


In almost every dialect of BASIC there are two commands which allow 
BASIC and machine language to work together. These commands are USR 
and CALL. 

Unfortunately, the USR function is not implemented in ST BASIC. An older 
version even admitted this with the message Function not yet 
implemented when the function was called. We will have to use the 
other function. 

CALL, as the name implies, calls a machine language program. The follow¬ 
ing parameters must be specified: 

CALL A (PI, P2, P3) 

A is the address of the machine language program. P1 , P 2 , and P 3 are 
parameters which are passed to the program. The number of parameters 
passed can be set by the user, from 0 on up. 

If a specific value (such as 1) is given, it will be taken as such. If a variable 
is used, its contents will be taken. It should be noted that the values are 
passed in a longword, so that only integer values between ± 2 billion are 
possible. 


321 


Abacus 


Atari ST Disk Drives Inside and Out 


If a string variable is passed (such as A$), the address of the string in 
memory will be taken. This avoids having to use varptr, which is 
required for calculating the start address of the program. 

The machine language program finds the following parameters on the stack: 

First, the return address, to which control of the processor will be returned 
when RTS is encountered. This value is usually uninteresting, but it may 
not be changed! 

Then comes a word which contains the number of parameters passed. This 
word can be accessed simply with the command MOVE . w 4 (SP) , DO, 
whereby the number will be placed in DO. 

The longword following contains a pointer to the parameter list itself. This 
pointer can be loaded into address register AO, for example, with the 
command MOVE A . L 6 ( SP ) , AO. 

The parameter list contains the parameters in the order in which they were 
specified in the BASIC call. These values can be processed by the machine 
language program. 

We encountered a peculiar effect while working with this function. Some 
programs ran without difficulty, while others, some of them very simple, 
caused the computer to crash. After a good deal of hair-pulling, we came to 
the solution of the puzzle: Address register A6 may never be used or 
changed by the machine language program! After changing all references to 
A6 in the programs to A4, everything worked fine. 


322 


Abacus 


Atari ST Disk Drives Inside and Out 


8.2 Some example programs 


In the following sections we will present some subroutines for BASIC 
programs. Hopefully, you will find some utilities which you can use for 
your own applications. In addition, the example programs show how 
various parameters can be used and exchanged. You can then write your 
own machine language programs which can improve and speed up your 
BASIC programs. 

The examples are always given in assembly language form and as BASIC 
listings. The BASIC programs also contain loaders which generate the 
machine language programs. You can also place the data for the machine 
language program in a file on a disk and then read it into the array with the 
command BLOAD " filename", A. This requires an additional disk 
access, but it makes the BASIC program shorter and easier to read. 


8.2.1 BASIC/TOS interface 


The operating system of the Atari ST offers a large number of functions, but 
many of them cannot be accessed from within BASIC. This problem can be 
easily solved with the help of a machine language program, however. Such 
a program must be able to accept an arbitrary number of parameters from the 
calling BASIC program and pass them to the operating system on the stack. 

The program below possesses this capability. It offers a universal interface 
between BASIC and the operating system. The program can be called with 
an arbitrary number of parameters. The single restriction is that only 16-bit 
data (words) are accepted. A longword must be broken up into two parts. 

The last parameter which is specified in the CALL command has a special 
meaning. Because some GEMDOS functions return a value, this value will 
be placed in the last address specified. The example program demonstrates 
the function Conin, which waits for a key to be pressed and then returns the 
value of this key. 

Let's first take a look at the machine language program itself. The 
parameters are placed on the stack in a loop, and then sent to the operating 
system with a TRAP command. The return value, which is found in data 
register DO, will be written into the address of the last parameter. 


323 




Abacus 


Atari ST Disk Drives Inside and Out 


/** BASIC-TOS interface 6/86 S.D. ** 
;** call with CALL ADR (parameter list,x) ** 
;** with x as address of the return value DO ** 


run: 


move 

4(sp),d0 

/number of parameters 

move.1 

6(sp),a5 

/pointer to parameter block 

subq 

#2, dO 

/correct number of parameters 

move.1 

sp, a4 

/save old stack pointer 


loop: 


move.1 

(a5)+,dl 

/get parameters 

move 

dl, -(sp) 

/and put on stack 

dbra 

dO,loop 

/continue 

trap 

#1 

/call TOS 

move.1 

(a5),a5 

/return address 

move.1 

dO, <a5) 

/return DO 

move.1 

a4, sp 

/repair stack 

rts 


/done! 

end 




As you see, the program is very simple. We will therefore move right on to 
the BASIC program, which creates the machine language program and then 
tries it out. The function used is the Conin function, which waits for a 
keypress and returns the value of the key in DO. The lower word of DO 
contains the ASCII value of the key and the upper word contains the scan 
code. Both values are contained in the longword DO, which is written into 
the string variable B$. 

10 '** BASIC-TOS interface S.D. ** 

20 defdbl s 

30 dim a%(200) 

40 a=varptr(a%(0)) 

50 s=0 

60 bload "a:batosint.b",a 
100 b$=space$(10) 

110 b=varptr(b$) r'address for return 

120 call a (l,b) :'call the routine 

130 ?peek(b),(mid$(b$,4,1)):'output the result 
1000 '** data for BASTOS ** 

1010 data &H302F,4,&H2A6F,6,SH5540,SH284F,SH221D,&H3F01 
1020 data SH51C8,&HFFFA,SH4E41,SH2A55,&H2A80,&H2E4C, &H4E75 


324 




Abacus 


Atari ST Disk Drives Inside and Out 


8.2.2 Directory reader 


An annoying defect of ST BASIC is its inability to read the directory of a 
disk. The DIR command can be used to display the directory on the screen, 
but what good is that? If we want to use the directory information in a 
program, we have to use a machine language program again. This section 
contains such a program. In addition to the normal access to the filenames, 
it can also return all of the additional information stored in the directory (see 
section 6.3). It also returns the total and remaining capacity of the current 
disk. 

Let's look at the machine language program first 

/** Directory for BASIC S.D. ** 


run: 


bra 

sf irst 

snext: 


move 

#$4 f,-( sp) 

trap 

#1 

addq.1 

#2, sp 

tst 

dO 

bne 

nothing 

rts 


sfirst: 


cmp 

#3, 4(sp) 

bne 

quit 

move.1 

6(sp),a5 

lea 

buffer(pc), 

move.1 

8(a5),(a4) 

move.1 

8(a5) , - (sp) 

move 

#$la,-(sp) 

trap 

#1 

addq.1 

#6, sp 

move 

6 (a5) , - (sp) 

move.1 

(a5) , - (sp) 

move 

#$4e,-(sp) 

trap 

#1 

addq.1 

#8, sp 


;entry 1 
;entry 2 
;SNEXT function 

;no more entries 

;not 3 parameters! 

/pointer to parameter block 
a4 

/save buffer address 
/buffer address 
/SETDTA function 

/Attribute 
/Filename 

/SFIRST function 


325 




Abacus 


Atari ST Disk Drives Inside and Out 


tst 

dO 


bne 

nothing 


quit: 

rts 


;=> BASIC 

nothing: 

move.1 

buffer(pc) 

, a4 

clr 

- (sp) 

;drive 

move.1 

a4, -(sp) 

/buffer address 

move 

#$36,-(sp) 


trap 

#1 

;GET-FREE-SPACE function 

addq.1 

#8, sp 


move.1 

#'Free',30(a4) ;no filename! 

rts 


;=> BASIC 


buffer: dc.l 0 


end 


The first things we notice about the program are the two entry points. This 
is because the program actually consists of two programs. 

The first part is the the SFIRST function. This GEMDOS function must be 
given some parameters like search name, file attribute, and buffer address. 
The function of the other program section, SNEXT, doesn't need any 
parameters, because the settings made in the last SFIRST call are used 
again. 

For the calling BASIC program this means that it must first call the program 
at the beginning and then continue with the address + 4. The parameters 
need be passed only once. 

If the SFIRST or the SNEXT function does not find a file which 
corresponds to the search criteria, another function will be called. This 
function returns a parameter block which contains the information about the 
total size and remaining space on the disk. This information is received by 
the BASIC program in the same parameter block as the directory entries. 

The first call to the program runs 

CALL S (F$, A, B$) 


326 


Abacus 


Atari ST Disk Drives Inside and Out 


The parameters: 

S specifies the starting address of the machine language program. 

F$ is a string containing the pathname of the file(s) to be searched for 
(such as B: \* . BAS). The string must be terminated by a zero byte! 

A is the attribute which the file(s) must have. A zero searches for all 
normal files. 

B$ designates a string which serves as a buffer for the data returned by 
the machine language program. See section 6.3 for the layout of this 
buffer. 

Here is a BASIC program which generates the machine language program 
and shows how it is used. All files on the disk in the current drive are 
displayed, together with their lengths. Following this is the capacity of the 
disk in bytes. 

10 '** read directory S.D. ** 

15 clearw 2: fullw 2: gotoxy 0,0 
20 defdbl s 

30 dim a% (200) 

40 d=varptr(a%(0)) :'lst entry for SFIRST 

50 s=0 

60 for i=0 to 52 :read a%(i) 

70 s=s+a%(i) :next i 

80 if so 610895 then ?"error !":stop 

130 dl=d+4 : 1 2nd entry for SNEXT 

140 input "Disk Drive :",f$ 

150 f$=f$+":\*.*"+chr$(0) :'search string 

160 p$=space$(50) clear buffer 

170 call d (f$,0,p$) :'SFIRST 

180 goto lopl 

190 loop: 

200 call dl SNEXT 

210 lopl: 

220 if mid$(p$,31,3) = "Fre" then 260 :'end 

230 i=27: gosub calc :'calculate length 

235 for z=31 to 50: if asc(mid$(p$,z,1)) = 0 then x=z-31:z=51 

236 next z 

240 ?mid$(p$,31,x),1 :'output name and length 

250 goto loop 

260 end 

290 calc: 

300 l=asc(mid$(p$,i+3,l))+SH100*asc(mid$(p$,i+2,1)) 

310 l=l + &H10000*asc(mid$ <p$,i+1,1)) 

320 return 


327 




Abacus 


Atari ST Disk Drives Inside and Out 


1000 '** Data for BASDIR ** 

1010 data SH6000,&H12,&H3F3C,SH4F,SH4E41,SH548F,&H4A40 
1020 data &H6600,SH3C,&H4E75,SHC6F,3,4,SH6600,SH2E,SH2A6F 
1030 data 6,&H49FA,&H42,SH28AD,8,SH2F2D,8,&H3F3C 
1040 data SHI A,SH4E41,SH5C8F,&H3F2D,6,&H2F15,SH3F3C,&H4E 
1050 data SH4E41,&H508F,&H4A40,SH6600,4,&H4E75,SH287A,SH18 
1060 data &H42 67,SH2F0C,SH3F3C,SH36,SH4E41,SH508F,&H297C 
1070 data SH4672,&H6569,&H1E,SH4E75,0, 0 


8.2.3 Read/write sectors 


The data on a disk, as we have said before, are stored in sectors. These 
sectors cannot normally be accessed directly because the operating system 
loads only the sectors which the selected file occupies. 

If we want to be able to access sectors at random, we need a machine 
language program that can read or write a single sector. We will present 
such a program. 

Three parameters are passed to the program: the logical sector number, a 
read or write instruction, and the address of the buffer. 

The logical sector number can be from 0 to the maximum value. This 
maximum depends on the disk format used. The read/write instruction can 
have the following values: 

0 - read a sector 

1 - write a sector 

2 - read a sector, ignore disk changes 

3 - write a sector, ignore disk changes 

If command 0 or 1 is used, the program accesses only the disk currently in 
the drive. Changing the disk results in no access being made. 

The machine language program looks like this: 

;** Read sector S.D. ** 

;** CALL A (sector,rw (2=read,l=write),buffer) ** 


run: 

cmp #3,4(sp) ;3 parameters ? 

bne quit ;no => terminate 


328 


Abacus 


Atari ST Disk Drives Inside and Out 


move.1 

6(sp),a5 

clr 

- (sp) 

move 

2(a5) , — (sp) 

move 

#l,-(sp) 

move.1 

8(a5),-(sp) 

move 

6(a5) , - (sp) 

move 

#4,- (sp) 

trap 

#13 

add. 1 

#14,sp 


quit: 

rts 


/pointer to parameters 

/drive A 

/I sector 
/buffer 
/read/write 
/RWABS function 
/BIOS call 


;=> BASIC 


end 


The program accesses drive A only. If this has to be made variable, the 
program can be rewritten for four parameters. 

Here is the corresponding BASIC program which creates the machine 
language program and gives a small demonstration: 

10 '** Read/write sector from disk drive A. S.D. ** 

15 clearw 2: fullw 2: gotoxy 0,0 
30 dim a%(100),f%(300) 

40 a=varptr(a%(0)) 

50 defdbl s 

60 s=0 

70 for i=0 to 22: read a% (i) :'load ml program 

80 s=s+a%(i) :next i 

90 if s<> 165974 then ?"Error in DATA! " :stop 

100 f=varptr(f%(0)) 

200 input "Sector, rw : "/s%,r% 

210 call a (s%,r%,f) :'Call the program 

220 for i=0 to 255 

230 if (i mod 16)=0 then ? 

240 ?mki$(f%(i)); ASCII output of sectors 

250 next i :? 

1000 '** Machine language data ** 

1010 data &HC6F,3,4,&H6600,SH24,&H2A6F,6,SH4267 
1020 data SH3F2D,2,&H3F3C,1,SH2F2D,8,SH3F2D,6 
1030 data &H3F3C,4,&H4E4D,&HDFFC,0,SHE,&H4E75 


329 


Abacus 


Atari ST Disk Drives Inside and Out 


8.2.4 Any disk format 


As we mentioned in Chapter 6, 3 1/2" disks can use a variety of formats. 
The number of sides used, tracks, and sectors per track are all variable. 

In order to format a disk from within a BASIC program, we need some help 
from a machine language subroutine, since there is no corresponding 
command in the BASIC instruction set. In additon, even using the Desktop 
limits us to two different formats. We will write a small machine language 
program which can be called from BASIC and supplied with some 
parameters. These parameters define the format which will be used to 
initialize the disk. 

The program itself is similar to the one we saw in Chapter 6. On closer 
examination, we'll notice some important differences. 

First of all, the menu is missing and the parameter calculation connected 
with it. All of the important settings are taken directly from the calling 
BASIC program. Second, the variables are addressed differently. This is 
more complicated because the program will be read into an area of memory 
unknown to it by a BASIC loader. All addressing must therefore be relative. 

The machine language program is called by a CALL command with the 
following construction: 

CALL A (S,T,SPT,DRV) 

The variables used have the following meanings: 

A is the memory address at which the machine language program 

was placed. In the previous example this is the address of the 
integer array A% as determines by the VARPTR function. 

S stands for the number of sides which are to be formatted on the 

disk. The number of sides - 1 is passed, so that S=0 formats a 
single-sided disk and S=1 a double-side disk. 

T specified the number of tracks. Normally a disk contains 80 

tracks, but it is physically possible to format up to 82 tracks 
(sometimes even 83). 


330 


Abacus 


Atari ST Disk Drives Inside and Out 


SPT are the sectors per track. Normally this is 9, but it is possible to 
format 1 to 10 sectors per track. 

DRV stands for drive. This variable determines the drive in which the 
disk will be formatted. 0 indicates drive A and 1 is used for 
drive B. Please don't try to format the RAM disk (drive C) by 
using a 3 here; this accesses both drives A and B at the same 
time, instead of the RAM disk. 

Here now is the machine language program which takes the parameters 
from the BASIC program and formats the disk: 

;** BASIC subroutine: formatting routine S.D. ** 

run: 

move 4(sp),dO 
cmp #4,d0 

bne quit 

move.l 6(sp),a5 

lea sides(pc),a4 

move.l (a5)+,dl 
move dl, (a4) 
move.l (a5)+,dl 
move dl,2(a4) 
move.1 (a5)+,dl 

move dl,4(a4) 
move.1 (a5)+,dl 

move dl,6(a4) 


move 

tracks(pc),8(a4) 


subq 

#1,8(a4) 


floop: 

move 

sides(pc),10(a4) 

/determine side 

floopl: 

bsr 

fmttr 

/format track 

bne 

quit 


sub 

#1,10(a4) 

/side -1 

bpl 

floopl 


sub 

#1, 8(a4) 


bpl 

floop 

/next track 

setboot: 

clr 

- (sp) 

/execute flag 

moveq 

#2, dO 



;sides 
;tracks 

/sectors per track 
/drive number 


/4 parameters? 

/no => terminate 

/pointer to parameter block 


331 


Abacus 


Atari ST Disk Drives Inside and Out 


or 

sides(pc),dO 


move 

dO, -(sp) 

;disk type, sides 

move.1 

#$1000000,-(sp) 

/create seriual number 

pea 

12(a4) 

/buffer address 

move 

#$12,-(sp) 


trap 

#14 

/create boot sector 

add. 1 

#14,sp 


lea 

12(a4),aO 


clr. 1 

dO 


cmp 

#9,4(a4) 

/9 sectors per track? 

beq 

sok 

/yes 

move. b 

#10,24(aO,dO) 

/set 10 SPT 

move 

tracks(pc),dl 


tst 

04) 

/I side? 

beq 

sdll 

/yes 

lsl 

#1, dl 

/else double-sided 

sdll: 



bsr 

addsec 

/SEC + number of tracks 

sok: 



cmp 

#80,2(a4) 

/80 tracks? 

beq 

trok 


move 

#18,dl 


tst 

04 ) 

/I side? 

beq 

sdl2 

/yes 

lsl 

#1, dl 

/else double-sided 

sdl2 : 



bsr 

addsec 

/SEC + 2*9 or 4*9 

trok: 



move 

#1, -(sp) 

/I sector 

clr .1 

- (sp) 

/side 0, track 0 

move 

#1, -(sp) 

/sector 1 

move 

drive(pc),-(sp) 

/drive 

clr .1 

- (sp) 


pea 

12 04) 

/buffer 

move 

#9,-(sp) 


trap 

#14 

/flopwr 

add.l 

#20,sp 


quit: rts 


/return to BASIC 

addsec: 


/SEC = SEC + Dl 

move.b 

20 (aO,dO),d2 

/HI 

lsl 

#8,d2 


move.b 

1900,dO) ,d2 

/LO 


332 


Abacus 


Atari ST Disk Drives Inside and Out 


add dl,d2 

move.b d2,19(a0,d0) ;set LO 

lsr #8,d2 

move.b d2,20(a0,d0) ;set HI 

rts 

fmttr: 

clr 

move.1 
move 
move 
move 
move 
move 
clr. 1 
pea 
move 
trap 
add. 1 
tst 
rts 

sides: dc.w 1 

tracks: dc.w 80 

secptr: dc.w 9 

drive: dc.w 0 

tracksl: dc.w 80 
side: dc.w 0 

buffer: dc.w $200 

end 

The program is completely relocatable, meaning that it will run at any 
memory address. The individual components of the program have already 
been explained in other parts of this book. 

The BASIC program below calls the formatting routine. It contains a loader 
which generates the machine language program from DATA statements. The 
machine language program can also be loaded from disk, of course. 

10 '** Format a diskette ** 

15 clearw 2: fullw 2: gotoxy 0,0 

17 defdbl s 

20 dim a% (400) 

30 a=varptr(a%(0)):s = 0 
40 for i=0 to 144: read a%(i) 


- (sp) 

#$87654321,-(sp) 
#l,-(sp) 
side(pc),- (sp) 
tracksl(pc),-(sp) 
secptr(pc),-(sp) 
drive(pc),-(sp) 

- (sp) 

12(a4) 

#10,-(sp) 

#14 

#26,sp 
dO 


/format one track 
/virgin data 
/magic number 
/interleave 
/ side 
/track 

/sectors/track 
/drive 


/ flopfmt 
/test for error 


333 



Abacus 


Atari ST Disk Drives Inside and Out 


45 

46 
50 
100 
110 
120 
130 
140 
150 
160 
170 
180 
190 
200 
210 
220 
230 
240 
250 
260 
270 
280 
290 
300 
310 
320 
330 
340 
350 
360 


s =s +a%(i) : next i 

if s <> 1033402 then ?"error !":stop 

?"Extended disk formatter":?:? 

?"sides 0= single 1= double":? 

?"tracks 79-83" :? 

?"sectors/track 9/10":? 

?"drive a=0 b=l":? 

print "sides, tracks, sectors/track, drive " 
input s,t,spt,dr 
call a (s,t,spt,dr) 

'** Data for BFORMAT.obj ** 

data 4H302F,4H0004,4H0C40,4H0004,4H6600,SH00CC, 
data 4H49FA,4H0110,4H221D,4H3881,4H221D,SH3941, 
data 4H3941,4H0004,4H221D,4H3941,4H0006,SH397A, 
data 4H536C,4H0008,4H397A,4H00EC,SH000A,&H6100, 
data 4H0096,4H046C,4H0001,4H000A,SH6A00,4HFFF0, 
data SH0008,SH6A00,&HFFE0,4H4267,4H7002,4H807A, 
data SH2F3C,SH0100,4H0000,4H486C,4H000C,SH3F3C, 
data 4HDFFC,4H0000,4H000E,SH41EC,4HOOOC,SH4280, 
data SHO004,&H6700,4H0018,SH11BC,4H000A,4H0818, 
data 4H4A54,4H6700,4H0004,4HE349,4H6100,4H003E, 
data 4H0002,4H6700,4HO012,4H323C,4H0012,4H4A54, 
data 4HE349,4H6100,4H0024,4H3F3C,4H0001,4H42A7, 
data 4H3F3A,4H0066,4H42A7,4H486C,4H000C,4H3F3C, 
data 4HDFFC,4H0000,4H0014,4H4E75,4HI430,4H0814, 
data 4H0813,4HD441,4H1182,4H0813,4HE04A,4HI182, 
data 4H4267,4H2F3C,4H8765,4H4321,4H3F3C,4H0001, 
data 4H3F3A,4H0028,4H3F3A,4H0020,4H3F3A,4H001E, 
data 4HOOOC,4H3F3C,4H000A,4H4E4E,4HDFFC,4HOOOO, 
data 4H4E75 


4H2A6F,4H0006 
4H0002,4H221D 
4H00F8,4H0008 
4H00B4,4H6600 
4H046C,4H0001 
4H0OC6,4H3F00 
4H0012,4H4E4E 
4H0C6C,4H0009 
4H323A,4H0096 
4H0C6C,4H0050 
4H6700,4H0004 
4H3F3C,4H0001 
4H0009,4H4E4E 
4HE14A,4H1430 
4H0814,4H4E75 
4H3F3A,4H002E 
4H42A7,4H486C 
4H001A,4H4A40 


8.2.5 Searching for data 


One use of machine language subroutines is data searching in arrays. For 
long lists a search can take so long in BASIC that it's not worth doing. Just 
think of a database which took several minutes to find a telephone number. 

A machine language program which performs this task is quite easy to 
write. It consists of just three parts: 

1. Code to get parameters from BASIC 

2. A search loop 

3. Code to return the result to the BASIC program 


334 



Abacus 


Atari ST Disk Drives Inside and Out 


Here is such a program: 


lopl: 


loop: 


okl: 


quit: 


t 

Search 

in integer array S.D. ** 

/** CALL 

, A (start- 

•of-array,number,search word) ** 

cmp 

13, 4 (sp) 

;3 parameters? 

bne 

quit 

;no => exit 

move.1 

6(sp),a5 

/pointer to parameters 

move.1 

(a5),a4 

/pointer to parameter field 

tst 

(a4) + 

/set to f%(1) 

move.1 

4(a5) , dl 

/number of data 

move . 1 

8(a5),d2 

/search word 

moveq 

#1 , d3 

/ index=l 

cmp 

(a4)+,d2 

/ compare 

beq 

okl 

/ found 

addq 

#1, d3 

/ index+1 

cmp 

d3, dl 

/end? 

bne 

loop 

/no 

move 

#-l,d3 

/not found! 

move . 1 

(a5),a5 

/address for return 

move 

d3,(a5) 

/return index 

rts 


/=> BASIC 

end 




This small program accomplishes the search in fractions of a second and 
returns the number of the desired entry in the first element of the list. For 
this reason you should use only elements 1 to n for the list data. If an 
element is not found, -1 will be returned. 

Since there are so many uses for this program, the following loader and 
example program is very simple. The principle of the routine and its use will 
be clear, however. 


10 

30 

40 


'** Search in integer array S.D. 
dim a%(60),f$(1000) 
a=varptr(a%(0)) 


335 


★ ★ 


Abacus 


Atari ST Disk Drives Inside and Out 


50 defdbl s 

60 s=0 

70 for i=0 to 25 :read a%(i) 

80 s=s+a%(i) :next i 

90 if so 211865 then ’"error !" :stop 

130 f=varptr(f%(0)) 

140 for i%=l to 8 

150 read f%(i%) :'read example values 

170 next i% 

180 clearw 2: fullw 2: gotoxy 0,0 

190 ?"Machine Language search of integer array" :? 

195 ? "Array contains - 6,2,99,345,7,3,0,4":? 

200 input "Integer to search for : ";s% 

210 call a (f,i%,s%) 

220 if f%(0)=-l then ?"** Not found ! **" :goto 200 

230 ?s%;" is entry #";f%(0) :goto 200 

1000 '** Data for machine language program ** 

1010 data SHC6F,3,4,SH6600,&H2A,&H2A6F,6,SH2855 
1020 data SH4A5C,SH222D,4,&H242D,8,SH7601,SHB45C,SH6700 
1030 data SHE,SH5243,&HB243,&H6600,SHFFF4,SH363C,&HFFFF 
1040 data SH2a55,SH3A83,SH4E75 
1100 data 6,2,99,345,7,3,0,4 


8.2.6 Sort data 


Sorting large quantities of data is a very time-consuming process. A BASIC 
progrmn to sort 1000 items would create a disturbingly long pause, which 
can disturb the course of the program. A machine language program to do 
the same thing, on the other hand, is significantly faster. 

Such a program will now be presented. It is designed to sort any large 
integer array from a BASIC program in ascending order. The program is 
passed the address of the start of the array and the number of entries to be 
sorted as parameters. This also allows a portion of the array to be sorted. 

The algorithm used in this program is very simple. It isn't the fastest 
algorithm available, but that doesn't matter much given the high speed of the 
68000 microprocessor. 

Here is the machine language routine: 

;** Sort integer array S.D. ** 

;** CALL A (start-of-array,number) ** 


336 


Abacus 


Atari ST Disk Drives Inside and Out 


run: 

cmp #2,4 (sp) ;2 parameters? 

bne quit ;no => exit 

move.l 6(sp),a5 /pointer to parameters 

lopl: 

move.1 (a5),a4 

move.l 4(a5),dl 

clr d3 

lop2 : 

move (a4), dO 

cmp 2(a4),d0 

ble okl 

move 2(a4),(a4) 

move dO,2(a4) 

st d3 

okl: 

addq.l #2,a4 

subq.l #l,dl 

bne lop2 

tst d3 /done? 

bne lopl /no => continue 

quit: 

rts ;—> BASIC 

end 

Here is a BASIC program which contains the machine language program in 
DATA statements and which reads it into an array. Various values are then 
placed into another array. The input is ended with -1. The machine language 
routine is then called which sorts the data in the entire array. The sorted 
values are then printed. 

This use is only intended as an example, of course. Things become more 
interesting when the quantities of data are much larger and the speed 
advantage over a straight BASIC program becomes clear. 

10 '** Sort an integer array S.D. ** 

20 defdbl s 

30 dim a%(200) 

40 a=varptr(a%(0)) :s = 0 
60 for i=0 to 28 :read a%(i) 

70 s=s+a%(i) :next i 


/pointer to parameter field 
/number of data 
/clear exchange flag 


/compare 
/OK 

/exchange 

/set exchange flag 
/next value 


337 



Abacus 


Atari ST Disk Drives Inside and Out 


80 

100 

110 

120 

130 

135 

136 

137 
140 
150 
160 
170 
180 
190 
200 
210 
1000 
1010 
1020 
1030 
1040 


if s<> 280743 then ?"error !":stop 


dim f%(1000) 
defint i 
a=varptr(a%(0)) 
f=varptr(f% (1)) 
clearw 2: fullw 2:gotoxy 
?"Sort an integer array" 
?"Enter -1 to end input" 
for i=l to 1000 
input "Entry : ";f%(i) 
if f%(i)=-l then 180 
next i 

call a (f,i-2) 
for j=l to i 
?j;" : ";f%(j) 
next j 


:'prepare data field 

address of ml program 
:'address of data 
0 , 0 
? 

7 

:'enter data 
: ' end? 

:'no, continue 
:'sort 

:'and output 


'** Data for BASSORT ** 

data &HC6F,2,4,&H6600,&H30,&H2A6F,6,SH2855 
data SH222D,4,SH4243,SH3014,SHB06C,2,SH6F00,SHC 
data &H38AC,2,SH3940,2,SH50C3,£H548C,SH5381,SH6600 
data SHFFE6,&H4A43,&H6600,&HFFD8,&H4E75 


8.2.7 Reading the date and time 


Every database program intended for use in everyday life must be able to 
process the current date and time. Unfortunately, ST BASIC doesn't have 
any functions like this, so we'll need a machine language program again. 

The program presented here reads the clock time and the date from the 
computer and returns both of these to the BASIC program which called it. 
This information is also formatted so that it can be processed directly. 

The call is done simply by CALL A ( A$ ), whereby the result will be placed 
in the string variable A$. The format used is the following: 

HH.MM.SS. DD.MM.YYYY 

III III 

III II - Year (such as 1986) 

III I - Month (such as 07 for July) 

I | | -Day 

I I - Seconds (in two-second steps) 

I - Minutes 

- Hours (0 to 23) 


338 









Abacus 


Atari ST Disk Drives Inside and Out 


July 3, 1986 at 10:16 PM and 30 seconds would appear in A$ as 22.16.30. 
03.07.1986. 

Here is the machine language program which reads the time and date, 
formats it, and returns it to the BASIC program: 

;** Read clock time S.D. ** 

;* Call with CALL A (A$) results in A$ * 

;* HH.MM.SS. MM.DD.YYYY., time and date * 


run: 


cmp 

#1,4(sp) 

;one parameter? 

bne 

quit 

;no => terminate 

move.1 

6(sp),a5 

/pointer to parameter list 

move.1 

(a5),a5 

/pointer to string 


go: 


move 

#$2c,-(sp) 


trap 

#1 

/get time BIOS function 

addq.1 

#2, sp 


and. 1 

#$ffff,dO 

/mask out upper word 

move.b 

#':',d6 

/colon seperator 

move 

a 

o 

a 


lsr 

#8, dl 


lsr 

#3, dl 

/hours 

bsr 

set2b 

/set hours 

move.1 

dO, dl 


lsr 

#5,dl 


and 

#%111111,dl 


bsr 

set2b 

/set minutes 

move.1 

dO, dl 


lsl 

#1, dl 

/seconds *2 

and 

#$3f,dl 

/and mask 

bsr 

set2b 

/set seconds 

move.b 

#' 1 ,(a5)+ 

/set space 

move 

#$2a,-(sp) 


trap 

#1 

/get date BIOS function 

addq.1 

#2, sp 


and. 1 

#$ffff,dO 

/mask out upper word 


339 



Abacus 


Atari ST Disk Drives Inside and Out 


move.b 

#'/',d6 

/ / separator 

move.1 

dO, dl 


lsr 

#5, dl 


and 

#%1111,dl 

/mask month 

bsr 

set2b 

/set month 

move.1 

dO, dl 


and 

#%11111,dl 

/mask day 

bsr 

set2b 

/set day 


move.1 

dO, dl 


lsr 

#8, dl 


lsr 

#1, dl 


and 

#%1111111,dl 

/mask year 

add 

#80,dl 

/correct 

move.b 

#'l',(a5)+ 


move.b 

#'9',(a5)+ / 

prepare 19oo 

bsr 

set2b / 

set year 


quit: 

rts ;ready ! 

set2b: /output D1 with two characters 

divu #10,dl 

add.l #$300030,dl /correct ASCII value 

move.b dl,(a5)+ /HI nibble 

swap dl 

move.b dl,(a5)+ /LO nibble 

move.b d6,(a5)+ /set back-slash 


end 

Here again is the corresponding BASIC program which creates the machine 
language program and demonstrates how it is used: 

10 ■** GET_TIME in BASIC S.D. ** 

20 defdbl s 

30 dim a%(200) 

40 a=varptr(a% (0)) 

50 s=0 

55 'bload "b:readclk.b",a 

60 for i=0 to 83 :read a$: a%(i) =val("&H"+a$) 

70 s=s+a%(i) :next i 

80 if int(s)<> 272454 then ’"error !":stop 


340 


Abacus 


Atari ST Disk Drives Inside and Out 


90 t$=space$(20) 

100 call a (t$) 

110 ? "Today is right$(t$,10) 

120 ? "The time : left$(t$,8) 

990 '** Data for GETTIME ** 

2000 DATA 0C6F,0001,0004,6600,0082,2A6F,0006,2A55 
2010 DATA 3F3C,002C,4E41,548F,COBC,0000,FFFF,1C3C 
2020 DATA 003A,3200,E049,E649,6100,0062,2200,EA49 
2030 DATA C27C,003F,6100,0056,2200,E349,C27C,003F 
2040 DATA 6100,004A,1AFC,0020,3F3C,002A,4E41,548F 
2050 DATA COBC,0000,FFFF,1C3C,002F,2200,EA49,C27C 
2060 DATA 000F,6100,0028,2200,C27C,001F,6100,001E 
2070 DATA 2200,E049,E249,C27C,007F,D27C,0050,1AFC 
2080 DATA 0031,1AFC,0039,6100,0004,4E75,82FC,00OA 
2090 DATA D2BC,0030,0030,1AC1,4841,1AC1,1AC6,4E75 
2100 DATA 0000,0000,0000,0000 


8.3 Programming the FDC in BASIC 

There are a fairly large number of disk monitors available for the Atari ST. 
Unfortunately, all of the ones which we are familiar with use only the 
routines which the operating system offers. This suffices for most 
applications, but if we want to know exactly what information is hidden on 
the disk, we need some functions which can be performed only by 
accessing the floppy disk controller directly. 

Such functions include reading the ID fields on a track, reading an entire 
track, or custom-formatting a track. 

Our suggestion: Write your own disk monitor to include functions like this. 
In BASIC? Sure, why not? If the floppy controller functions are available, 
it's quite possible to do this in BASIC. But these functions can't be 
accessed via the operating system. The GEMDOS, BIOS, and XBIOS can't 
help us any more. 

To give us what we need, we wrote a collection of routines which can be 
bound into a BASIC program and which make all of the FDC commands 
available in BASIC. 

The times when sectors weren't readable because the operating system 
insisted on the "proper" ID field will be gone. If you get a message like 


341 



Abacus 


Atari ST Disk Drives Inside and Out 


Drive A: does not respond. . ., you can search the disk 
thoroughly and find out what's wrong. 

Naturally, you have to able to interpret the results which are returned by the 
less-used FDC commands. You will find all the information you need in the 
chapter on the WD1772 floppy disk controller. 

There are other advantages that make full use of the flexibility of our 
BASIC/FDC interface. It is always possible to change the command words. 
These always contain some "option bits," which can influence the execution 
of the commands. Moreover, a single FDC command can be used to read or 
write all of the sectors on a track. It is also possible to format just part of a 
track, something which could be useful for a copy protection scheme. 

But first things first, and first we need the FDC interface. The application 
possibilities will be explained later. 


8.3.1 The BASIC/FDC interface program 


Let's start with the machine language program which represents our 
interface to the FDC. 

There are three ways of getting this program into memory: 

1. Enter the assembly language source (the version printed here was 
produced with the AssemPro macroassembler) and assemble it. 

2. Enter the BASIC listing and start it with RUN. 

3. Order the optional diskette for this book. 

First comes the assembly language listing, which shows how our 
FDC/BASIC interface works internally. Those who know both assembly 
language and BASIC will find all of the routines needed to operate the FDC 
printed here. It shouldn't be any trouble to appropriate some of the routines 
here for use in your own programs. 

The BASIC programmer (to whom this chapter is dedicated) must excuse 
this little excursion into the world of machine language programming. Since 
direct programming of the FDC is also of general interest, we feel required 
to publish the assembly language listing as well as the BASIC listing. 


342 


Abacus 


Atari ST Disk Drives Inside and Out 


If you are only interested in the finished product or you only know ST 
BASIC, skip this section and continue with the BASIC loader 
FDCCREAT. BAS, which creates the machine language program. 

.**********★********★********************************************* 

.******* FDC/BASIC INTERFACE ******** 

****************************************************************** 


/Hardware registers 


dmamode 

dmascnt 

dmalow 

dmamid 

dmahigh 

giselect 

giwrite 

mfp 


$ff8606 
$ff8604 
$ff860d 
$ff860b 
$ff8609 
$ff8800 
$ff8802 
$fffaOl 


/Control words 


for the 


DMA controller 


(DMA data direction => READ) 


srcmd 

srtrk 

srsec 

srdat 

srcnt 


$80 / select command register 

$82 / select track register 

$84 / select sector register 

$86 / select data register 

$90 / select DMA sector-count register 


/control words 


for the DMA controller 


(DMA data direction -> WRITE) 


swcmd = $180 / same as for => READ 

swtrk = $182 

swsec = $184 

swdat = $186 

swcnt = $190 

.***************************************************************** 

r 

align 
STart: 


bra. 

s run 

/ to start of 

program 






• ★ * ★ ★ 
/ 

★★★★★★★ 

★★★★★★★★★★★★A 

Command 

words 

* ★ ★ ★ 

******************* 

★ ★ 

rest: 

dc ,w 

$01 / Restore 

MO, 

3ms 

Step 

rate 



see: 

dc. w 

$11 / Seek 

MO, 

3ms 

Step 

rate 



stp: 

dc. w 

$31 / Step 

MO, 

3ms 

Step 

rate. 

update track 

reg 

stpi: 

dc.w 

$51 / Step-in 

MO, 

3ms 

Step 

rate. 

update track 

reg 


343 





Abacus 


Atari ST Disk Drives Inside and Out 


stpo: 

dc. w 

$71 

; Step-out 

MO 

rsec: 

dc.w 

$90 

; Read-Sector 

MO 

wsec: 

dc. w 

$b0 

; Write-Sector 

MO 

radr: 

dc.w 

$c0 

; Read-Address 

MO, 

rtrk: 

dc. w 

$e0 

; Read-Track 

MO 

wtrk: 

dc.w 

$f0 

; Write-Track 

MO 

fore: 

dc.w 

$d0 

; Force-Interrupt 


******************** Parameters 


3ms Step rate, update track reg. 
multiple 

multiple, write precompensation 

write precompensation 


prm: dc.w 00 

dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.w 00 
dc.l 00 
dc.l 00 
dc.l 00 
dc.l 00 
dc.l 00 
dc.l 00 


function number 
drive number 
track number 
sector number 

number of bytes to transfer 

number of ID fields to read 

FDC status 

DMA status 

timeout? (l=timeout) 

number of bytes to transfer 

DMA start address 

DMA end address 

address of the track buffer 

address of the sector buffer 

address of the ID buffer 

address of the ID status buffer 


• ★★★★*★******★**★ Hgits wg go ★★★★★*★★★★★★★★★★★ 


run: 

tst.w 4(sp) ; parameters passed? 

bne exit ; yes, return to BASIC 

;Since the source can only be addressed PC relative, we use A3 
;as the program counter. 

LEA STart(PC),A3 ; PROGRAM START IN ADDRESS REG. 3 

MOVEM.L D0-D7/A0-A6,SAVREG-STart(A3) ; SAVE REGISTERS 

******************** g e t supervisor mode *********************** 

clr.l -(sp) ; user stack => superv. stack 

move.w #$20,-(sp) ; command => Super 


344 



Abacus 


Atari ST Disk Drives Inside and Out 


trap #1 

addq.l #6,sp ; correct stack 

MOVE.L DO,SAVSTACK-STart(A3) ; SAVE OLD STACK POINTER 


;*** Clear some flags and calculate absolute address of the *** 
;*** desired function. *** 


LEA PRM-STart(A3),A5 

move.w #1,$43e ; 

move.w #0,16(a5) ; 

MOVE.W #0,DMA-STart(A3) 
MOVE.W #0,VBLFLAG-STart(A3) 


; pointer to parameter block 

disable floppy VBL 
clear timeout flag 
; clear DMA flag 
; clear VBL reset flag 


move.w 0(a5),d0 
and.1 #$0f,dO 
lsl.l #2,dO 


; get function number 
; there are only 16 functions (0-15) 
; times 4 = functab offset 


LEA FUNCTAB-STart(A3),A4 
move.l 0(a4,d0),d0 


; func. table address 
relative start address of the routine 


jsr 0 (a3,dO) 


; +program start=abs. addr. of routine 


TST.W VBLFLAG-STart(A3) 
beq letoff 
move.w 40,$43e 


; VBL on (after deselecting)? 
; no 

; turn on 


letoff: 


.****************** back to user mode ******************** 

MOVE.L SAVSTACK-STart(A3),DO ; GET OLD STACK POINTER BACK 
move.l dO,-(a7) ; pass old stack pointer 

move.w #$20,-(sp) ; command => Super 

trap #1 

addq.l #6,sp ; correct stack 

MOVEM.L SAVREG-STart(A3),D0-D7/A0-A6 ; RETURN REGISTERS 
exit: 

rts ; back to BASIC 

; That was it! (All) we have left are the following routines 


345 


Abacus 


Atari ST Disk Drives Inside and Out 


************************ Restore FDC **************************** 

restore: 

move.w #srcmd,dmamode 
MOVE.W REST-STart(A3),D7 
bsr wrtl772 
bsr fdcwait 


.*********************** seek TRACK **************************** 
seek: 

move.w #srdat,dmamode 
move.w 4(a5),d7 
bsr wrtl772 
move.w #srcmd,dmamode 
MOVE.W SEE-STart(A3),D7 
bsr wrtl772 
bsr fdcwait 


.************************ step ********************************* 
step: 

move.w #srcmd,dmamode 
MOVE.W STP-STart(A3), D7 
bsr wrtl772 
bsr fdcwait 
rts 

.************************* step in ***************************** 
stepin: 

move.w #srcmd,dmamode 
MOVE.W STPI-STart(A3),D7 
bsr wrtl772 
bsr fdcwait 


stepout: 


; select FDC command reg 
; STEP IN command 
; write command 
; wait until FDC is ready 


; select FDC command reg 
; STEP command 
; write command 
; wait until FDC ready 


; select data reg 
; track number in d7 
; write track number 
; select command reg 
; SEEK command 
; write command 
; wait until FDC ready 


; select command reg 
; RESTORE command 
; pass command 
; wait until FDC is ready 


346 




Abacus 


Atari ST Disk Drives Inside and Out 


move.w #srcmd,dmamode ; select FDC command reg 

MOVE.W STPO-STart(A3),D7 ; STEP OUT command 

bsr wrtl772 ; write command 

bsr fdcwait ; wait until FDC is ready 

rts 


;*********************** Force Interrupt *********************** 
Force: 

MOVE.W FORC-STart(A3),D7 ; FORCE INTERRUPT command 

bsr wrtl772 ; write command 

move.w #$100,d7 ; delay loop 

wtfrc: 

dbra d7,wtfrc 
rts 

.********************* READ SECTOR(S) ************************** 

readsector: 

; DMA address to sector buffer 


move.1 32(a5),d7 
bsr setdma 

MOVE.W #l,DMA-STart(A3) 
move.w #srcnt,dmamode 
move.w #swcnt,dmamode 
move.w #srcnt,dmamode 
move.w #$0c,d7 
bsr wrtl772 

move.w #srsec,dmamode 
move.w 6(a5),d7 
bsr wrtl772 

move.w #srcmd,dmamode 
MOVE.W RSEC-STart(A3),D7 
bsr wrtl772 

bsr fdcwait 
bsr readstat 
rts 


; SET DMA G 
; toggle DMA R/W 

; select DMA sector count 
; load with 12 (corresponds to 6kB) 
; load DMA sent 

; select sector reg 
; sector number in d7 
; write sector number 

; select command reg 

; READ MULTIPLE SECTORS command 
; write command 

; wait until FDC is ready 
; read status and number of bytes 


.********************** Read Address *************************** 
readaddress: 

move.l 40(a5),a4 ; load address of the status buffer 


347 




Abacus 


Atari ST Disk Drives Inside and Out 


move.l 36(a5),d7 
bsr setdma 

move.w #srcnt,dmamode 
raove.w #swent,dmamode 
move.w #srcnt,dmamode 
move.w #$01,d7 
bsr wrtl772 
move.w #srcmd,dmamode 
move.w 10(a5),d4 
and.w #$7f,d4 
idloop: 

MOVE.W RADR-STart(A3),D7 

bsr wrtl772 

bsr fdewait 

move,b dO,(a4) + 

tst.w 16(a5) 

dbne d4,idloop 

bsr readstat 

rts 


; DMA address to ID field buffer 

; toggle DMA R/W 

; select DMA sector count 
; load with 1 (corresponds to 512 bytes) 

; select FDC command reg 
; #ID fields in D4 
; but only max. 128 

; READ ADDRESS command 
; write command 
; wait until FDC is ready 
; save status in buffer 
; timeout ? 

; no, read next ID field 
; read status and number of bytes 


•★★★*★*★*******★* 


READ TRACK **************************** 


readtrack: 


move.1 28(a5),d7 
bsr setdma 

MOVE.W #1,DMA-STart(A3) 
move.w Isrcnt,dmamode 
move.w #swcnt,dmamode 
move.w #srcnt,dmamode 
move.w #$0e,d7 
bsr wrtl772 
move.w #srcmd,dmamode 
MOVE.W RTRK-STart(A3),D7 
bsr wrtl772 
bsr fdewait 
bsr readstat 
rts 


; DMA address to track buffer 

; SET DMA G 
; toggle DMA R/W 

; select DMA sector count 
; load with 14 (corresponds to 7kB) 

; select command reg 
; READ TRACK command 
; write command 
; wait until FDC is ready 
; read status and number of bytes 


.********************* WRITE SECTOR(S) 




writesector: 

move.l 32(a5),d7 
bsr setdma 

MOVE.W #1,DMA-STart(A3) 
move.w #swent,dmamode 


DMA address to sector buffer 

; SET DMA G 
toggle DMA R/W 


348 




Abacus 


Atari ST Disk Drives Inside and Out 


move.w #srent,dmamode 
move.w #swcnt,dmamode 
move.w #$0c,d7 
bsr wrtl772 
move.w #swsec,dmamode 
move.w 6(a5),d7 
bsr wrt!772 


; select DMA sector count 
; load with 12 (corresponds to 6kB) 
; write DMA sent 
; select sector reg 
; sector number in d7 
; write sector reg 


move.w tswcmd,dmamode 

MOVE.W WSEC-STart(A3),D7 

bsr wrtl772 

bsr fdewait 

bsr readstat 

rts 


; select command reg 

; WRITE MULTIPLE SECTORS command 
; write command 
; wait until FDC is ready 
; read status and number of bytes 


•****★**★*★★★★*******★* WRITE TRACK 




writetrack: 


move.l 28(a5),d7 
bsr setdma 

MOVE.W #l,DMA-STart(A3) 
move.w #swent,dmamode 
move.w tsrent,dmamode 
move.w #swcnt,dmamode 
move.w #$0e,d7 
bsr wrtl772 
move.w #swcmd,dmamode 
MOVE.W WTRK-STart(A3),D7 
bsr wrtl772 
bsr fdewait 
bsr readstat 
rts 


; DMA address to track buffer 

; SET DMA G 
; toggle DMA R/W 

; select DMA sector count 
; load with 14 (corresponds to 7kB) 
; write DMA sent 
; select command reg 

; WRITE TRACK command 
; write command 
; wait until FDC is ready 
; read status and number of bytes 




;Those were the routines that access the WD1772 commands 

;We now have more subroutines, which are called partially from the 

;main routines and partially directly from BASIC (such as setdrive) 


.****************** Read sector register 




rsecreg: 

move.w #srsec,dmamode ; select sector reg 

bsr readl772 ; and read 


349 



Abacus 


Atari ST Disk Drives Inside and Out 


and.w #$ff,dO 
move.w dO,6(a5) 
move.w #srcmd,dmamode 
rts 


; only lower byte 
; into FDC array 
; select command reg 


•**★★*★**★★***** 


read track, register ********************** 


rtrkreg: 


move.w #srtrk,dmamode 
bsr readl772 
and.w #$ff,dO 
move.w dO,4(a5) 
move.w #srcmd,dmamode 
rts 

.********************* 

r 


; select track reg 
; and read 
; lower byte only 
; into FDC array 
; Select command reg. 

read status reg *********************** 


rstareg: 


move.w fsrcmd,dmamode 
bsr readl772 
and.w #$ff,dO 
move,w dO,12(a5) 
rts 


; select status reg 
; and read 

; status in lower byte 
; into FDC array 


********************* write track reg 




wtrkreg: 


move.w #srtrk,dmamode 

move.w 4(a5),d7 

and.w #$ff,d7 

bsr wrtl772 

move.w # s r cmd,dmamode 

rts 


; select track reg 
; get track number 

; and write 
; select command reg 


. *★★★★**★*★**★**' 


Set DMA transfer address ***************** 


setdma: 

move.1 d7,20(a5) 
move.b d7,dmalow 
lsr.l #8,d7 
move.b d7,dmamid 
lsr.l #8,d7 
move.b d7,dmahigh 


; save start address in FDC array 
; first the low byte 

; then the middle byte 

; and last the high byte 


350 



Abacus 


Atari ST Disk Drives Inside and Out 


move.l 20(a5),d7 
clr.l d6 
move.w 8(a5),d6 
add.l d6,d7 
move.l d7,24(a5) 
rts 


; get start address back 

; number of bytes to transfer 
; add the two 
; =expected end address 


;*** Read DMA status; calculate number of transferred bytes *** 
readstat: 


move.w dmamode,dO 
and.w #$7,d0 
move.w dO,14(a5) 

clr.l dl 

move.b dmahigh,dl 
lsl.l #8,dl 
move.b dmamid,dl 
lsl.l #8,dl 
move.b dmalow,dl 

move.1 dl,24(a5) 
sub.1 20(a5),dl 
move.w dl,18(a5) 
rts 


; read DMA status 
; take lower 3 bit only 
; to fdcout 

; read DMA end address 


end address into array 
end addr minus start addr 
=number of bytes 




Write FDC register ******************* 


wrtl772: 


bsr wait 

move.w d7,dmascnt ; write FDC reg or DMA sector count reg 

bsr wait 

rts 




Read FDC register 




readl772: 
bsr wait 

move.w dmascnt,dO ; read FDC reg or DMA sector-count reg 

bsr wait 

rts 


351 




Abacus 


Atari ST Disk Drives Inside and Out 


***************** Wait until FDC is ready 




fdcwait: 


move.l #$180,d5 
litlwt: 

dbra d5,litlwt 

move.l #$40000,d5 
cmp.w #$9,0 (a5) 
bne readmfp 
move.l #$28000,d5 


; wait until Busy is set 

; d5 as timeout counter 
; READ-ADDRESS command? 

; yes, shorter timeout 


readmfp: 

btst #5,mfp 
beq fdcready 
subq.l #l,d5 
beq timeout 

TST.W DMA-STart(A3) 
beq readmfp 


; is command done? 

; yes 

; no, decrement timeout counter 
; if timedout 

; COMMAND W/ DATA TRANSFER? 

; no, keep testing 


MOVE.B DMAHIGH,TEMP+l-STart(A3) 
MOVE.B DMAMID,TEMP+2-STart(A3) 
MOVE.B DMALOW,TEMP+3-STart(A3) 
MOVE.L TEMP-STart(A3),D7 
cmp.1 24 (a5),d7 

bit readmfp ; no. 


; EXPECTED END DMA ADDRESS 
; REACHED? 


keep testing 


bsr force 

MOVE.W #0,DMA-STart(A3) 
bra fdcready 

timeout: 

move.w dmascnt,d0 
and.w #$ff,d0 
move.w dO,12(a5) 
bsr force 
move.w #l,16(a5) 
rts 


if so, then terminate command 
; CLEAR DMAFLAG 
and end routine normally 


read status before termination 
mask out top byte 
and into array 
terminate command 
set timeout flag 


fdcready: 

move.w dmascnt,d0 
and.w #$ff,d0 


; read status 
; mask out top byte 


352 


Abacus 


Atari ST Disk Drives Inside and Out 


move.w d0,12(a5) ; and into FDC array 

rts 

.************ Wait until motor is off ***************** 
motoroff: 

move.w #srcmd,dmamode 
test: 

bsr readl772 
btst #7,dO 
bne test 
rts 

.************************* Wa i t ***************************** 
wait: 

move.w sr,-(a7) 
move.w #$20,d5 
wt2 : 

dbf d5,wt2 
move.w (a7)+,sr 
rts 

.***************** s e i ec t drive and side **************** 
setdrive: 


; save status 
; d5 as counter 

; get status back 


; select status reg 

; and read 
; Motor on set? 

; yes, keep waiting 


clr.l d7 

move.w 2(a5),d7 ; 

bne set 

bsr motoroff ; 

MOVE.W #1,VBLFLAG-STart (A3) 
set: 

eor.b #7,d7 
and.b #7,d7 
move.w sr,-(a7) 
or.w #$700,sr 
move.b #$e,giselect 
move.b giselect,dO 
and.b #$f8,d0 
or.b d0,d7 
move.b d7,giwrite 
move.w (a7)+,sr 
rts 


get drive number 

if 0, delselect when motor off 
; SET VBL RESET flag 

invert bits for hardware 

only the lower 4 bits are affected 

save status 

turn off interrupts 

select port A of the sound chip 

read port A 

clear bits 0-2 

set new bits 

write to port A 

restore status 


353 





Abacus 


Atari ST Disk Drives Inside and Out 


•★*★★★*★★★***★*★★***★*★*★★★*****★★★★★★***★*★*★★★★******★★******* 

;******************* Variables and tables ******************** 
• ★***★******★★*★*★★**★■*★★********★***★*★***★**★★***★ 


align 

SAVREG: ds.L 16,0 

savprm: dc.l 0 

savstack: dc.l 0 


vblflag: dc.w 0 
dma: dc.w 0 
temp: dc.1 0 


FUNCTAB: DC.L RESTORE-STart,SEEK-STart 

DC.L STEP-STart,STEPIN-STart 
DC.L STEPOUT-STart,READSECTOR-START 
dc.1 writesector-start,readtrack-start 
dc.l writetrack-start,readaddress-start 
dc.l force-start,setdrive-start 
dc.l rsecreg-start,rtrkreg-start 
dc.l rstareg-start,wtrkreg-start 


align 






end 

Now we come to the listing of the BASIC program FDCCREAT . BAS. This 
program creates the file FDCINTER. IMG, which can later be bound into a 
BASIC program. This works with other versions of BASIC, such as GfA 
BASIC , in addition to ST BASIC. 

10 .*************** FDCCREAT.BAS A.S. *************** 

15 

20 ?:fullw 2:clearw 2:gotoxy 0,0 

25 ? "File >> fdcinter.img « is being created":?:?:? 

30 dim c%( 688):cs#=0 

35 for i=0 to 688 

40 read a$:c%(i)=val("SH"+a$) 

45 check#=check#+(c%(i)) 

50 next i 

55 if check#= 2458472.96 then 70 
60 ?"Something is wrong with the DATA." 

65 goto 80 


354 




Abacus 


Atari ST Disk Drives Inside and Out 


70 bsave "fdcinter.img",varptr(c%(0)), 1378 
75 ? "The program >> fdcinter.img << has been written. 

80 ?:?:?:’"Press a key":a=inp(2):end 

85 ' 

90 >***»***** DATA for fdcinter.img ********* 

95 

100 DATA 6042,0001,0011,0031,0051,0071,0090,00B0 

101 DATA 00C0,00E0,00F0,00D0,0000,0000,0000,0000 

102 DATA 0000,0000,0000,0000,0000,0000,0000,0000 

103 DATA 0000,0000,0000,0000,0000,0000,0000,0000 

104 DATA 0000,0000,4A6F,0004,6600,0074,47FA,FFB2 

105 DATA 48EB,7FFF,04D2,42A7,3F3C,0020,4E41,5C8F 

106 DATA 2740,0516,4BEB,0018,33FC,0001,0000,043E 

107 DATA 3B7C,0000,0010,377C,0000,051C,377C,0000 

108 DATA 051A,302D,0000,0280,0000,000F,E588,49EB 

109 DATA 0522,2034,0800,4EB3,0800,4A6B,051A,6700 

110 DATA 000A,33FC,0000,0000,043E,202B,0516,2F00 

111 DATA 3F3C,0020,4E41,5C8F,4CEB,7FFF,04D2,4E75 

112 DATA 33FC,0080,00FF,8606,3E2B,0002,6100,02EA 

113 DATA 6100,0306,4E75,33FC,0086,OOFF,8606,3E2D 

114 DATA 0004,6100,02D4,33FC,0080,OOFF,8606,3E2B 

115 DATA 0004,6100,02C4,6100,02E0,4E75,33FC,0080 

116 DATA OOFF,8606, 3E2B, 0006, 6100,02AE, 6100, 02CA 

117 DATA 4E75,33FC,0080,OOFF,8606,3E2B,0008,6100 

118 DATA 0298,6100,02B4,4E75,33FC,0080,OOFF,8606 

119 DATA 3E2B,000A,6100,0282,6100,029E,4E75,3E2B 

120 DATA 0016,6100,0274,3E3C,0100,51CF,FFFE,4E75 

121 DATA 2E2D,0020,6100,0202,377C,0001,051C,33FC 

122 DATA 0090,OOFF,8606,33FC,0190,OOFF,8606,33FC 

123 DATA 0090,OOFF,8606,3E3C,000C,6100,023C,33FC 

124 DATA 0084,OOFF,8606,3E2D,0006,6100,022C,33FC 

125 DATA 0080,OOFF, 8606,3E2B,000C, 6100, 021C, 6100 

126 DATA 0238,6100,01E0,4E75,286D,0028,2E2D,0024 

127 DATA 6100,01A6,33FC, 0090,OOFF, 8606, 33FC, 0190 

128 DATA OOFF,8606,33FC,0090,OOFF,8606,3E3C,0001 

129 DATA 6100,01E6,33FC,0080,OOFF,8606,382D,OOOA 

130 DATA 0244,007F,3E2B, 0010, 6100,01CE,6100,01EA 

131 DATA 18C0,4A6D,0010,56CC,FFEC,6100,0188,4E75 

132 DATA 2E2D,001C,6100,0152,377C,0001,051C,33FC 

133 DATA 0090,OOFF,8606,33FC,0190,OOFF, 8606,33FC 

134 DATA 0090,OOFF,8606,3E3C,OOOE,6100,018C,33FC 

135 DATA 0080,OOFF,8606,3E2B,0012,6100,017C,6100 

136 DATA 0198,6100,0140,4E75,2E2D,0020,6100,010A 

137 DATA 377C,0001,051C,33FC,0190,OOFF,8606,33FC 

138 DATA 0090,OOFF,8606,33FC,0190,OOFF,8606,3E3C 

139 DATA 000C,6100,0144,33FC,0184,OOFF,8606,3E2D 

140 DATA 0006,6100,0134,33FC,0180,OOFF,8606,3E2B 


355 






Abacus 


Atari ST Disk Drives Inside and Out 


141 DATA 000E,6100,0124,6100,0140,6100,00E8,4E75 

142 DATA 2E2D,001C,6100,00B2,377C,0001,051C,33FC 

143 DATA 0190,OOFF,8606,33FC,0090,OOFF,8606,33FC 

144 DATA 0190,OOFF,8606,3E3C,OOOE,6100,OOEC,33FC 

145 DATA 0180,OOFF,8606,3E2B,0014,6100,OODC,6100 

146 DATA 00F8,6100,OOAO,4E75,33FC,0084,OOFF,8606 

147 DATA 6100,00D6,0240,OOFF,3B40,0006,33FC,0080 

148 DATA OOFF, 8606, 4E75, 33FC,0082,OOFF, 8606, 6100 

149 DATA 00B8,0240,OOFF,3B40,0004,33FC,0080,OOFF 

150 DATA 8606,4E75,33FC,0080,OOFF,8606,6100,009A 

151 DATA 0240,OOFF,3B40,OOOC,4E75,33FC,0082,OOFF 

152 DATA 8606,3E2D,0004,0247,OOFF,6100,006C,33FC 

153 DATA 0080,OOFF,8606,4E75,2B47,0014,13C7,FFFF 

154 DATA 860D.E08F,13C7,FFFF,860B,E08F,13C7,FFFF 


155 

DATA 

8609,2E2D,0014, 

156 

DATA 

0018,4E75,3039, 

157 

DATA 

OOOE,4281,1239, 

158 

DATA 

860B,E189,1239, 

159 

DATA 

0014,3B41,0012, 

160 

DATA 

8604,6100,OOCO, 

161 

DATA 

8604,6100,OOBO, 

162 

DATA 

FFFE,2A3C,0004, 

163 

DATA 

0008,2A3C,0002, 

164 

DATA 

6700,005c,5385, 

165 

DATA 

FFE8,1779,FFFF, 

166 

DATA 

0520,1779,FFFF, 

167 

DATA 

0018,6D00,FFC4, 

168 

DATA 

6000,001C,3039, 

169 

DATA 

OOOC,6100,FCEA, 

170 

DATA 

OOFF,8604,0240, 

171 

DATA 

0080,OOFF,8606, 

172 

DATA 

FFF6,4E75,40E7, 

173 

DATA 

4E75,4287,3E2D, 

174 

DATA 

377C,0001,051A, 

175 

DATA 

007C,0700,13FC, 

176 

DATA 

8800,0200,00F8, 

177 

DATA 

4E75,0000,0000, 

178 

DATA 

0000,0000,0000, 

179 

DATA 

0000,0000,0000, 

180 

DATA 

0000,0000,0000, 

181 

DATA 

0000,0000,0000, 

182 

DATA 

0000,0000,OOCO, 

183 

DATA 

0112,0000,0128, 

184 

DATA 

0200,0000,02A0, 

185 

DATA 

0492,0000,02E8, 

186 

DATA 

033A 


4286,3C2D,0008,DE86,2B47 
OOFF,8606,0240,0007,3B40 
FFFF,8609,E189,1239,FFFF 
FFFF,860D,2B41,0018,92AD 
4E75,6100,OOCA,33C7,OOFF 
4E75,6100,OOBA,3039,OOFF 
4E75,2A3C,0000,0180,51CD 
0000,0C6D,0009,0000,6600 
8000,0839,0005,OOFF,FA01 
6700,0030,4A6B,051C,6700 
8609,051F,1779,FFFF,860B 
860D,0521,2E2B,051E,BEAD 
6100,FDO6,377C,0000,051C 
OOFF,8604,0240,OOFF,3B40 
3B7C,0001,0010,4E75,3039 
OOFF,3B40,OOOC,4E75,33FC 
6100,FF50,0800,0007,6600 
3A3C,0020,51CD,FFFE, 4 6DF 
0002,6600,OOOC,6100,FFDO 
0A07,0007,0207,0007,40E7 
OOOE,OOFF,8800,1039,OOFF 
8E00,13C7,OOFF, 8802,46DF 
0000 , 0000 , 0000 , 0000,0000 
0000 , 0000 , 0000 , 0000,0000 
0000 , 0000 , 0000 , 0000,0000 
0000 , 0000 , 0000 , 0000,0000 
0000 , 0000 , 0000 , 0000 , 0000 
0000,00D6,0000,OOFC,0000 
0000,0150,0000,0248,0000 
0000,01A8,0000, 013E, 0000 
0000,0306,0000,0324,0000 


356 




Abacus 


Atari ST Disk Drives Inside and Out 


Assuming you didn't make any mistakes when entering the listing, the 
machine language program FDCINTER. IMG should be available, which 
makes it possible to call all of the FDC commands and a bit more. 

The comments in the listing in the next section tell how these routines can be 
accessed from BASIC. 

Passing parameters to fdcinter. img 

Before we look at the demonstration program, we would like to get 
acquainted with the machine language program first. We will assume that 
you want to integrate this program into your BASIC programs, perhaps just 
because of a few individual functions. For such an application it is tedious 
to look through the various listings to find the information you need. 

Let's start with an overview which lists which parameters must be passed to 
which commands and add some explanations. 


Input parameters 

Funct 

number 

Drive 

number 

number 

Start sector 
number 

Number of bytes 
to be transfer red 

Number of D 
fields to be read 

Starting addr. 
of track buffer 

Starting addr. 
of sector buffer 

Starting addr. ol 
ID field buffer 

Starting addr. of 

C status buffer 

FUNCTION 

FDC%(12) 

FDC%(13) 

FDC%(14) 

FDC%(15) 

FDC%(16) 

FDC%(17) 

FDC%(28) 

FDC%(27) 

FDC%(28) 

FDC%(29) 

FDC%(30) 

FDC%<31) 

FDC%<32) 

FDC%<33) 

RESTORE 

00 


XX 








SEEK 

01 










STEP 

02 










STEP IN 

03 










STEP OUT 

04 










READ SECTOR 

05 



HSBI 

xx (2) 



xxxx (4) 



WRITE SECTOR 

08 



mom 

xx (2) 






READTRACK 

07 




xx (2) 


E32H 




WRITE TRACK 

08 




xx (2) 






READ ADDRESS 

09 





xx P) 



E391 

xxxx (4) 

FORCE NTERRUPT 

10 










SELECT DRIVE 

11 

XX 









READ SECTOR REG 

12 










READ TRACK REG. 

13 










READ STATUS REG 

14 










WRITE TRACK REG. 

15 


XX 









Input parameters 


(1) The number of the first record to be written or read is entered in 
FDC% ( 15) . Note that this specification always refers to the track over 


357 

























































Abacus 


Atari ST Disk Drives Inside and Out 


which the read/write head is currently positioned. If you want to work 
with "logical" sector numbers, these must be converted to absolute 
track/ sector addresses. 

(2) The number of sectors to be written or read is indirectly entered in 
FDC% (16) via the number of bytes to be transferred. At first this 
appears needlessly complicated, but it has the advantage that formats 
with varying sector sizes can be correctly written or read. 

For example, if 5 Atari format sectors are to be transferred, a value of 
5*512 is loaded in FDC% ( 16 ). For a format with a sector length of 
256 bytes, the same number of sectors would be specified as 5*256. It 
is also possible to use this"multiple sector access" with formats in 
which varying sector lengths occur in a track. If for some "copy 
protection format" four successive sectors are to be read whose sector 
lengths are 1024, 512, 256, and 128 bytes (doesn't matter which 
order), it is sufficient to pass 1024+512+256+128 in FDC% (16) . It is 
also possible, for instance, to read or write just half a sector. Just enter 
the appropriate number of bytes. 

The same applies to the READ TRACK and WRITE TRACK com¬ 
mands. If an entire track is to be processed by the call, pass a value 
greater than 6300. With a lower value you can cause just part of a track 
to formatted, for example. Through multiple formatting you can create 
properties in the track which would thoroughly confound the most 
dedicated software cracker. 

Very important: If data are written (WRITE SECTOR, WRITE 
TRACK), 32 ($20) must be added to the number of bytes to be 
transferred. The DMA controller loads 32 bytes into its internal 
registers in order to be ready for the data transfer. This means, for 
example, that the data for two sectors (2*512 bytes= $400) won't be 
completely transferred until DMA end address is incremented to $420 
more than the start address. 

(3) The number of ID fields to be read is limited to 128. This is generally 
enough to read all of the ID fields for even the strangest formats. The 
number - 1 is always placed in FDC% ( 17 ). At least 3 fields must be 
read before the DMA controller will transfer the data to the buffer. In 
order to put all of the ID information into memory, the value (#ID 
fields*6) must be divisible by 16 (see also: FDC command description: 
READ ADDRESS). 


358 




Abacus 


Atari ST Disk Drives Inside and Out 


(4) The start addresses of the buffers do not have to be given for each call. 
Generally this is done just once, as in our demo program. If the 
information for several tracks is to be stored at one time, simply 
dimension more arrays, the start addresses of which are passed before 
the call. Since addresses are always long words, this can be done 
simply with POKE. Let's say we have a second sector buffer: 

dim sec2% (3200) :def seg=0:poke fdc#+56,varptr(sec2%(0)) 

Parameters returned from fdcinter.img 

Naturally we get a number of parameters back from the machine language 
program. These are listed in the following table: 


Output parameters 

Track 

number 

Sector 

number 

FDC- 

STATUS 

D MA¬ 
ST ATUS 

Timeout 

DMA starting 
address 

DMA ending 
address 

Number of bytes 
to be transferred 

FUNCTION 

FDC%<14) 

FDC%( 15) 

FDC%<18) 

FDC%(19) 

FDC%(20) 


FDC%(24) 

FDC%<25) 

FDC%<21) 

RESTORE 



XX 


XX 




SEEK 



XX 


XX 




STEP 



XX 


XX 




STEP IN 



XX 


XX 




STEP OUT 



XX 


XX 




READ SECTOR 



XX 

XX 

XX 

xxxx 

xxxx 

XX 

WRITE SECTOR 



XX 

XX 

XX 

xxxx 

xxxx 

XX 

READ TRACK 



XX 

XX 

XX 

xxxx 

xxxx 

XX 

WRITE TRACK 



XX 

XX 

XX 

xxxx 

xxxx 

XX 

READ ADDRESS 



XX 

XX 

XX 

xxxx 

xxxx 

XX 

FORCE INTERRUPT 









SELECT DRIVE 









READ SECTOR REG 


XX 







READ TRACK REG. 

XX 








READ STATUS REG 



XX 






WRITE TRACK REG. 










Output parameters 


In this overview you'll find the two array elements FDC% (14) and 
FDC% (15) again. These are the only parameters which are passed in both 
directions. Otherwise input and output parameters are strictly separated. 
This means that except for the READ SECTOR register and READ TRACK 
register, the input parameters are in no way changed by the machine 
language program. 


359 
















































































Abacus 


Atari ST Disk Drives Inside and Out 


We recommend that you see the section on status interpretation (section 
4.2.2.4) for information on the FDC status [FDC% (18) ]. Naturally, the 
general description of the FDC commands also helps. 

The DMA status [FDC% (19) ] is easy to explain. Only 3 bits are of interest 
to us. Bit 0 is set if no errors occurred in the DMA transfer. Bit 1 is set if 
the contents of the sector-count register in the DMA controller did not count 
down to zero. This register tells the DMAC the maximum number of data 
which may be transferred at the start address. You don't have to worry 
about this, though, because the machine language routine takes care of it. 
Bit 2 is a "copy" of the DRQ output of the FDC. After a command witha 
data transfer, bits 0 and 1 will be set if there were no errors. Therefore, 
FDC% (19) contains a 3. If this is not the case, the LOST DATA bit will 
also be set in the FDC status. 

The DMA start address contains the current buffer address. After a READ 
SECTOR command the sector buffer's start address can be found here. 

The DMA end address mirrors the buffer pointer of the DMA controller. 
This address minus the start address is output as the number of bytes 
transferred in FDC% (21) . Special attention should be paid to the 
interpretation of these specifications. In the read direction, the pointer will 
be incremented by 16 ($10) after receiving this many data bytes, and the 
bytes which were stored temporarily in the DMA controller will be 
transferred to the buffer at this time. In the write direction, 32 ($20) bytes 
will be fetched into this internal storage and the buffer pointer will 
incremented by this value. 

A timeout (FDC% (20) =1) should occur only rarely because the delay time 
of the machine language routine is measured generously and the FDC will 
have terminated the command on its own in the meantime—in case of an 
error. Since the FDC doesn't do this until after about 1.5 seconds, the delay 
time for the READ ADDRESS command is shorter. The reason for this is 
the following: You want to read 100 ID fields (we'll ignore the potential 
sensibility of that for the moment), and so you pass the value 99 in 
FDC% (17) before calling the READ ADDRESS command. The machine 
language program executes the READ ADDRESS command 100 times 
before it returns to BASIC. If the FDC didn't find any ID fields (and didn't 
find any 100 times), you would have to wait over 2 minutes for it to return. 
Something like this leads to turning the computer off, and we'd rather not 
provoke that. If the FDC can't read an ID field in the alloted time, the 
command will be terminated with FORCE INTERRUPT and the machine 
language program will return to BASIC. 


360 




Abacus 


Atari ST Disk Drives Inside and Out 


The command words for the FDC 

Another feature which makes our FDC interface universal has only been 
mentioned in passing so far. It involves the command words which are 
passed to the FDC. It would be too bad if we couldn't adapt to our own 
needs. We have provided this flexibility in our interface. This table shows 
where the command words are stored and to what values they are initialized. 


Command word for | 

is found in 

1 

is initialized with 

RESTORE | 

FDC%(1) 

1 

$01 

SEEK | 

FDC%(2) 

1 

$11 

STEP | 

FDC%(3) 

1 

$31 

STEP IN | 

FDC%(4) 

1 

$51 

STEP OUT | 

FDC%(5) 

1 

$71 

READ SECTOR | 

FDC%(6) 

1 

$90 

WRITE SECTOR I 

FDC%(7) 

1 

$B0 

READ ADDRESS 1 

FDC%(8) 

1 

$C0 

READ TRACK I 

FDC%(9) 

1 

$E0 

WRITE TRACK | 

FDC%(10) 

1 

$F0 

FORCE INTERRUPT | 

FDC%(11) 

1 

$D0 


The exact meaning of the option bits in the command words can be found in 
the FDC command descriptions elsewhere in this book. Note that the m-bit 
(for multi-sector read/write) is set for READ SECTOR and WRITE 
SECTOR. If you clear this bit, only one sector will be processed at a time. 


8.3.2 Demo 1—All FDC commands 


After so much information about a comparatively small machine language 
routine, it's finally time to see if it really does what we claim. As we 
mentioned in the previous section, this listing consists of two parts, 
whereby the first part is intended just to show how simple it is to include 
these routines in your own programs. Let's turn to the second part. 

This section of the listing is a program which is designed to show how the 
parameters are passed to the machine language routine before the function is 
called. In addition, it has a real "demo character" because it allows direct 
access to all of the FDC commands and also displays all of the information 
returned, from the status to the data. It will let you experiment with the 
floppy disk controller to your heart's content. 


361 









Abacus 


Atari ST Disk Drives Inside and Out 


The program consists mainly of an "info screen," which is divided into two 
parts: 

1. Twenty functions are listed in the top part, of which the first sixteen 
(0-15) are those which our FDC interface can perform. 

Before an FDC command (functions 0-10) is called, a drive must first 
be selected. This is done via function 11. The values passed is as 
follows: 

2 => drive A, side 0 

3 => drive A, side 1 

4 => drive B, side 0 

5 => drive B, side 1 
or 0 => deselect 

The drives are automatically deselected when you exit the program 
with function 19 (end). 

Since data is transferred by some of the functions, it would be too 
bad if we couldn't look at it. This is the purpose of menu options 
16-18. Bear in mind that you must read a track into memory before a 
sector can be read. 

NOTE: If you get the chance, modify this demo program to permit 
the buffer data to be changed. This would give you a complete disk 
monitor, with features that you probably won't find anywhere else. 

2. The lower section of the screen contains the various parameters which 
will be passed to the subroutine or which are passed back by the 
subroutine. The start addresses of all of the buffers are also listed. 

At first glance this mass of information looks rather confusing and 
may make calling the machine language program seem more 
complicated than it really is. If you use the table of input and output 
parameters and look at just the parameters which are relevant for a 
given call, you will see that at most only two parameters beside the 
function number have to be passed (excluding the start addresses of 
the buffers). For half of the functions, the function number is the 
only thing that has to be passed. 

The program prompts you for the parameters which are required by the 
individual functions, and displays the previous values. If you want to use 


362 


Abacus 


Atari ST Disk Drives Inside and Out 


the previous value of a given parameter, just press <Retum> when asked to 
enter a new value. 

Before we give you the program, let's go step by step through a call using 
FDC inter . BAS. This sample will show you the contents of the disk 
directory in drive A. 

a. Run FDCINTER . BAS. 

b. Type <1 l><Retum> to Select Drive. 

c. Type <2><Retum> to select drive A, side 0. 

d. Select Seek function by typing < 1 ><Retum>. 

e. Press <l><Retum> to select track number 1. 

f. Type <5><Retum> to Read sector. 

g. Type <3><Retum> for starting sector of 3. 

h. For the amount of bytes to be read, input <512><Retum> (input here 
must be in decimal—hexadecimal numbers will be ignored). 

i. Select <17><Retum> to display the sector buffer. 

j. The buffer will be displayed on the screen. 

100 o .***************************************************************** 

1010 '***** FDC interface for BASIC (part 1) A.S. (7/86) ***** 

1020 ****************************************************************** 
1030 If peek(systab)=1 then res=2 else res=l 

1040 'There is little preparation necessary in order to use the FDC 
1050 'routines. We need some memory for the routine itself and for the 
1060 'data which are necessary for the disk operations. We dimension a 
1070 'couple of integer arrays and get their start addresses for this. 
1100 ' 

1110 dim fdc%(700) :fdc# =varptr(fdc%(0)) 

1120 dim trk%(3200):trk# =varptr(trk%(0) ) 

1130 dim sec%(2600):sec# =varptr(sec%(0)) 

1140 dim adr%(768) :adr# =varptr(adr%(0)) 

1150 dim stat%(64) :stat#=varptr(stat%(0)) 

1160 • 

1170 'The disk routines will be loaded into the fdc% array 
1180 ' 

1190 bload "a:fdcinter.img",fdc# 

1200 ' 

1210 ' and the start addresses of the other arrays POKEd in. 

1220 ' 

1230 def seg =0 :' we POKE long words 
1240 ' 

1250 poke fdc#+52,trk# :' track buffer 
1260 poke fdc#+56,sec# :' sector buffer 
1270 poke fdc#+60,adr# :' ID field buffer 


363 


Abacus 


Atari ST Disk Drives Inside and Out 


1280 

1290 

1300 

1310 

1320 

1330 

1340 

1350 

1360 

1370 

1380 

1390 

1400 

1410 

1420 

1430 

1440 

1450 

1460 

1470 

1480 

1490 

1500 

1510 

1520 

1530 

1540 

1550 

1560 

1570 

1580 

1590 

1600 

1610 

1620 

1630 

1640 

1650 

1660 

1670 

1680 

1690 

1700 

1710 

1720 

1730 

1740 


poke fdc#+64,stat#: 1 ID status buffer 

That was it! The next section explains how the individual 
functions are called. 






This is just a small demo, but we still don't want to make it too 
spartan. Let's start with a small menu which displays the 
individual function numbers and their parameters. The functions 
are those which are processed by machine language routines, 
while 16-18 serve only for viewing the buffer. These functions 
can naturally be made easier to use. Function 19 ends 
this demo and deselects the drives. 


fullw 2 : width 255 
Menu: 

? : clearw 2 : gotoxy 0,0 


Available functions 

ii_H 


?" 0 => Restore 
?" 3 => Step in 
?"ector" 

h-» 

II II 

V V 

Seek 

Step 

out 


2 => 

5 => 

Step " 
Read s"; 

?" 6 => Write sector 

?"track" 

7 => 

Read 

track 


8 => 

Write " ; 

?" 9 => Read address 

?" Drive" 

10=> 

Force interrupt 

11=> 

Select"; 

?" 12=> Read sector reg. 
?"tatus reg." 

13=> 

Read 

track 

reg. 

14=> 

Read s"; 

?" 15=> Write track reg. 

16=> 

Disp 

track 

buffer 

17=> 

Disp s"; 


?"ector buffer" 

?" 18=> Display ID field 19=> End program" 

I 

?" Display all parameters 

o "_II 


? " 

Function 

FDC status 

: $ 

Track buffer :$" 

?" 

Drive 

DMA status 

: $ 

Sector buffer :$" 

? " 

Track 

Timeout 

: $ 

ID field buffer:$" 

?" 

Sector 

DMA start 

: $ 

ID field status:$" 

? " 

#Bytes 

$ DMA end 

:$" 


?" 

#Id's -1 

#DMA bytes 

:$" 



364 











Abacus 


Atari ST Disk Drives Inside and Out 


1770 ' 

1780 main: 

17 90 ’ ==============—==========—=============================== == == ====:: 

1800 gotoxy 12/res,9 :?right$(" "+str$(fdc%(12)),4) 

1810 gotoxy 12/res,10 :?right$(" "+str$(fdc%(13)),4) 

1820 gotoxy 12/res,11 :?right$(" "+str$(fdc%(14)),4) 

1830 gotoxy 12/res,12 :?right$(" "+str$(fdc%(15)),4) 

1840 gotoxy 12/res,13 :?right$(" "+hex$(fdc%(16)),4) 

1850 gotoxy 12/res,14 :?right$(" "+str$(fdc%(17)),4) 

1860 gotoxy 32/res,09 :?right$<" "+hex$(fdc%(18)),6) 

1870 gotoxy 32/res,10 :?right$(" "+hex$(fdc%(19)),6) 

1880 gotoxy 32/res,11 :?right$(" "+hex$(fdc%(20)),6) 

1890 gotoxy 32/res,12 :?right$(" "+hex$(fdc%(22))+hex$(fdc%(23)),6) 

1900 gotoxy 32/res,13 :?right$(" "+hex$(fdc%(24))+hex$(fdc%(25)),6) 

1910 gotoxy 32/res,14 :?right$(" "+hex$(fdc%(21)),6) 

1920 gotoxy 60/res,09 :?right$(" "+hex$(fdc%(26))+hex$(fdc%(27)),6) 

1930 gotoxy 60/res,10 :?right$<" "+hex$(fdc%(28))+hex$(fdc%(29)),6) 

1940 gotoxy 60/res,11 :?right$(" "+hex$(fdc%(30))+hex$(fdc%(31) ) , 6) 

1950 gotoxy 60/res,12 :?right$(" "+hex$(fdc%(32))+hex$(fdc%(33)),6) 

1960 ' 

1970 gotoxy 0,15:?spc(150); 

1975 gotoxy 0,17:?spc(30 ); 

1980 key: 

1990 gotoxy 1,15:?spc(50) 

2000 gotoxy l,15:input " Which function";func$:func=val(func$) 

2010 if func<0 or func>19 then menu 
2020 func=func+l 

2030 if func=20 then fdc%( 12 )=11:fdc%(13)=0:call fdc#:end 
2040 ’ 

2050 if func<17 then 2110 
2060 reset 

2070 func=func-16:clearw 2: 

2080 on func gosub dumptrk,dumpsec,dumpid 
2090 openw 2:goto key 
2100 ' 

2110 on func gosub a,b,c,d,e,f,g,h,i,j,k,1,m,n,o,p 
2120 gotoxy 1,17:?"Execute function (y/n) ?"; 

2130 if chr$(inp(2))<>"y" then main 
2140 call fdc# 

2150 goto main 


2160 

2170 

2180 




2190 ' 

2200 'Here are 16 functions which are supported by the machine language 
2210 'routine. Here you see what parameters must be set for the call 
2220 '"call fdc#". In many cases it is sufficient to pass the function 


365 




Abacus 


Atari ST Disk Drives Inside and Out 


2230 'number in fdc%(12). 

2240 * 

2250 ' 

22 60 ' ===== ===—:==—==:—= RESTORE ======== —===== ======= 

2270 a: 

2280 f dc%(12)=0 

2290 gotoxy 1,15:?"RESTORE - no parameters required"return : 

2300 ' 

2310 '=======—===—======= seek ======—==================== 

2320 b: 

2330 fdc%(12)=1 

2340 gotoxy 1,15:?"SEEK - Which track number (old=>"; 

2350 ?fdc%(14);")";:input v$:if len(v$)=0 then return 
2360 fdc%(14)=val(v$):return 
2370 ' 

2380 '==================== STEP =========================== 

2390 c: 

2400 fdc%(12)=2 

2410 gotoxy 1,15:?"STEP - no parameters required";:return 
2420 ' 

2430 ■==================== STEP IN =========================== 

2440 d: 

2450 fdc%(12)=3 

2460 gotoxy 1,15:?"STEP IN - no parameters required"return 
2470 ' 

2480 '==================== STEP OUT =========================== 

2490 e: 

2500 fdc%(12)=4 

2510 gotoxy 1,15:?"STEP OUT - no parameters required";:return 
2520 ' 

2530 '=============—===== read SECTOR (s) —.====—============-- 

2540 f: 

2550 fdc%(12)=5 

2560 gotoxy 1,15:?"READ SECTOR-Start sector (old=>"; 

2570 ?fdc%(15);")";:input v$:if len(v$)=0 then 2590 
2580 fdc%(15)=val(v$) 

2590 gotoxy 1,16:?"Number of bytes (old=>$";hex$(fdc%(16));")"; 
2600 input v$:if len(v$)=0 then return 
2610 fdc%(16)=val(v$):return 
2620 ' 

2 630 '====—=========—=== WRITE SECTOR(s) —--- 

2640 g: 

2650 fdc%(12)=6 

2660 gotoxy 1,15:?"WRITE SECTOR-Start sector (old="; 

2670 fdc%(15);")";:input v$:if len(v$)=0 then 2690 

2680 fdc%(15)=val(v$) 

2690 gotoxy 1,16:?"Number of bytes (old=>$";hex$(fdc%(16));")"; 


366 
















Abacus 


Atari ST Disk Drives Inside and Out 


2700 input v$:if len(v$)=0 then return 
2710 fdc%(16)=val(v$):return 
2720 ' 

2730 '========—========== READ TRACK ===—==============—======= 

2740 h: 

2750 fdc%(12)=7 

2760 gotoxy 1,15:?"READ TRACK - Number of bytes (old=>$"; 

2770 ?hex$(fdc%(16));")";:input v$:if len(v$)=0 then return 
2780 fdc%(16)=val(v$):return 
2790 ' 

2800 •===========—===== WRITE TRACK ========================== 

2810 i: 

2820 fdc%(12)=8 

2830 gotoxy 1,15:?"WRITE TRACK - Number of bytes (old=>$"; 

2840 ?hex$ (fdc%(16));")";:input v$:if len(v$)=0 then return 
2850 fdc% (16) =val (v$) -.return 
2860 ' 

2870 '=_================= READ ADDRESS --=====-——== : —=—==== 

2880 j: 

2890 fdc%(12)=9 

2900 gotoxy 1,15:?"READ ADDRESS - Number of ID fields-1 (old=>"; 

2910 ?fdc%(17);")";:input v$:if len(v$)=0 then return 
2920 fdc%(17)=val(v$)-.return 
2930 ' 

2940 ■=================== FORCE INTERRUPT =■—==—================= ; 

2950 k: 

2960 fdc%(12)=10 

2970 gotoxy l,15:?"FORCE INTERRUPT - no parameters required";:return 
2980 ' 

2990 '====================== Select drive ====================== 

3000 1: 

3010 fdc%(12)=11:gotoxy 1,15 

3020 ?"(X=drv/side): 2=A/0; 3=A/1; 4=B/0; 5=B/1; 0=deselect" 

3030 gotoxy 1,16:?"Drive (old=>";fdc%(13);") 

3040 input v$:if len(v$)=0 then return 
3050 fdc%(13)=val(v$)ireturn 
3060 ' 

3070 ■================ Read sector register ===================== 

3080 m: 

3090 fdc%(12)=12 

3100 gotoxy 1,15:?"READ SECTOR REGISTER - no parameters required"; 
3110 return 
3120 ' 

3130 ■================ Read track register ================= 

3140 n: 

3150 fdc%(12)=13 

3160 gotoxy 1,15:?"READ TRACK REGISTER - no parameters required"; 


367 
















Abacus 


Atari ST Disk Drives Inside and Out 


3170 return 
3180 ■ 

3190 '================ Read status register ======================== 

3200 o: 

3210 fdc%(12)=14 

3220 gotoxy 1,15:?"READ STATUS REGISTER - no parameters required"; 

3230 return 
32 4 0 ' 

3250 '==================== Write track register ===================== 

3260 p: 

3270 fdc%(12)=15 

3280 gotoxy 1,15:?"WRITE TRACK REGISTER - Track number (old=>"; 

3290 ?fdc%(14)input v$:if len(v$)=0 then return 
3300 fdc%(14)=val(v$):return 


3310 ' 

3320 '****************************************************************** 
3330 '****************************************************************** 
3340 ' 

3350 'The following functions (16-18) have nothing to do with the 
3360 ’machine language routine, and just display the buffer contents. 
3370 ' 

3380 '================== Display track buffer ======================== 


3390 dumptrk: 

3400 gotoxy 0,0:?"DISPLAY TRACK BUFFER (all values=>hex, (c)ontinue, 

3410 ?"(e) nd)":? 

3420 ?" BUFFER 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E OF 01234"; 
3430 ?"56789ABCDEF" 

3440 ?"- -... 

f 

3450 ?"-" 

3460 ch$=" " 

3470 ' 

3480 lcnt=0 

3490 for id = 1 to (fdc%(16)+1)-16 step 16 
3500 lcnt=lcnt+l 

3510 id%(1)=id-l:?" +";right$("0000"+hex$(id%(1)),4);" "; 

3520 for by=0 to 15:def seg =id+by:id%(1)=peek(trk#-l) 

3530 ?right$("00"+hex$(id%(1)),2);" "; 

3540 if id%(1)=7 or id%(l)=10 or id%(l)=13 then id%(l)=20 
3550 mid$(ch$,by+l,l)=chr$(id%(1));next by:?" ";ch$ 

3560 ’ 

3570 if lcnt<10 then 3610 
3580 lcnt=0:dum=inp(2) 

3590 if chr$(dum)="e" then id=70000:goto 3610 
3600 if chr$(dum)<>"c" then 3580 
3610 next id 

3620 ?"Done! Pres a key..."; 

3630 dum=inp(2):return 


368 












Abacus Atari ST Disk Drives Inside and Out 


3640 ' 

3650 '================= Display sector buffer ~ 


3660 dumpsec: 

3670 lcnt=0 

3680 gotoxy 0,0:?"DISPLAY SECTOR BUFFER (all values=>hex, (c)ontinue,"; 
3690 ?" (e)nd)":? 

3700 ?" BUFFER 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E OF 01234"; 
3710 ?"56789ABCDEF" 

3720 -- 

3730 ?"-" 

3740 ' 

3750 ch$=" 

3760 for id = 1 to (fdc%(16)+1)-16 step 16 
3770 lcnt=lcnt+l 

3780 id%(1)=id-l:?" + ";rights("0000"+hex$(id%(1)), 4); " 

3790 for by=0 to 15:def seg =id+by:id%(1)=peek(sec#-l) 

3800 ?rights("00"+hex$(id%(1)),2);" 

3810 if id%(1)=7 or id%(l)=10 or id%(l)=13 then id%(l)=20 
3820 mid$(ch$,by+l,1)=chr$(id%(1)):next by:?" ";ch$ 

3830 ' 

3840 if lcnt<10 then 3880 
3850 lcnt=0:dum=inp(2) 

3860 if chr$(dum)="e" then id=70000:goto 3880 
3870 if chr$(dum)<>"c" then 3850 
3880 next id 

3890 ?"Done! Press a key..."; 

3900 dum=inp(2):return 
3910 ' 

3920 '=================== Display ID fields ======================== 

3930 dumpid: 

3940 gotoxy 0,0:?"DISPLAY ID FIELDS (all values=>hex,(c)ontinue,(e)nd)" 
3950 ?:?" BUFFER TRACK SIDE SECTOR LENGTH CRC1 CRC2 FDC status" 

3960 --" 

3970 ' 

3980 lcnt=0 

3990 for id = 1 to (fdc%(17)+1)*6 step 6 
4000 lcnt=lcnt+l 

4010 id%(1)=id-l:?" +";rights("00"+hex$(id%(1)),2);" "; 

4020 for by=0 to 5:def seg =id+by:id%(1)=peek(adr#-l) 

4030 ?right$("00"+hex$(id%(1)),2);" ";:next by 

4040 def seg=id/6+1:id%(1)=peek(stat#-l) 

4050 ?" ";rights("00"+hex$(id%(1)),2) 

4060 ' 

4070 if lcnt<9 then 4110 
4080 lcnt=0:dum=inp(2) 

4090 if chr$(dum)="e" then id=1000:goto 4110 
4100 if chr$(dum)<>"c" then 4080 


369 









Abacus 


Atari ST Disk Drives Inside and Out 


4110 next id 

4120 ?'-'Done! Press a key..."; 

4130 dum=inp(2)ireturn 
4140 1 

4150 '========================= END =============: 


8.3.3 Demo 2—Copying disks 


The following BASIC program shows you another use of our FDC machine 
language routines, and demonstrates how easily the floppy controller can be 
accessed from BASIC. The result is a copy program which can duplicate a 
double-sided disk in about 85 seconds! 

It really isn't much work to write a program like this. The big limitation of 
the program is that it only works with two drives. This is because we didn't 
want to confuse the issue by using too many buffers. In ST BASIC the 
maximum array size is 32K. 

This prevents us from doing something like dim sec% (79, 2303) which 
would reserve enough room for half of a double-sided disk. We could 
reserve space with dim secl%(2303), sec2% (2303) , etc., but we 
don't really want to. This is, after all, just a demo, and we don't want to 
deprive you of the fun of improving on our ideas. 

We will read the information from two tracks at a time (front and back 
sides) and then write this at the equivalent tracks on the destination disk. If 
you were using just one drive, this would require 80 disk swaps, something 
few of us would ever care to try. 

The Desktop takes about 195 seconds to copy a double-sided disk. This is 
about 50% more time than our program requires for the same task (130 
seconds). 

This percentage is astonishingly low if we take into account the fact that the 
current track is constantly displayed. Also, there is an "overhead" en¬ 
countered each time the FDC subroutine is called (such as switching in and 
out of supervisor mode). Finally, the constantly changing selection status of 
the drives also takes some time. Despite these circumstances, 130 seconds 
is quite acceptable. 


370 




Abacus 


Atari ST Disk Drives Inside and Out 


A real "tune up" is easy to do if we remove the PRINT commands from the 
copy loop (lines 60, 66, 76, and 102) which are extremely slow in 
comparison to the copy time. In this case, we gain 45 seconds at the cost of 
our track display. Put another way: the copy time is cut to just 85 seconds! 

In this program we encounter a case which makes it necessary to change the 
command word, or at least write to the track register. Let's trace through the 
program starting with track 0. In connection with reading this track (front 
and back), a STEP IN is executed for drive A. The read/write head is then 
located over track 1 and the track register of the FDC also contains a 1. 

Now we have to write the information we just read to track 0 of drive B. If 
we don't intervene here, things will go wrong: 

The FDC will terminate the WRITE SECTOR command with 
Record not found because the track register contains 1, but the 
ID fields contain 0 for the track number. 

We can fix this in one of two ways: 

1. In the STEP IN command for drive A we can clear the u-bit in the 
command word, which will prevent the track register from being 
updated. 

2. After the STEP IN command for drive A, we can change the track 
register back to the previous value. In our program this could look 
like this: 

fdc%(12)=15 : fdc%(14)=track : call fdc# 

We chose the first option. The command word for each STEP IN command 
must be changed, because we do want the drive B STEP IN command to 
update the track register. The track register only has to be loaded once for 
each track, but it would require an extra call fdc#. Even when it is 
executed twice, it is still faster to solve the problem by changing the 
command word. 

One last comment regarding the number of bytes to be transferred: In the 
read direction, the desired number is always given. For nine sectors in a 
track (512 bytes/sector), this is 9 * $200 = $1200. This is completely 
logical. Things are different in the write direction, however. The number 
here is 9 * $200 + $20. 


371 



Abacus 


Atari ST Disk Drives Inside and Out 


1 '* Copy program for two drives and double-sided disks A.S. * 

2 ' 

3 'We need 3 arrays, for the machine langauge program and as 

4 'sector buffers for track 0 and track 1 

5 ' 

6 dim fdc%(700),secO%(2400),secl%(2400):def seg=0 

7 ' 

8 'Load the machine language program 

9 ' 

10 fdc#=varptr(fdc%(0)):bload "a:fdcinter.b",fdc# 

11 ' 

12 'Get the start address of the two buffers 

13 ' 

14 sec0#=varptr(sec0%(0)):secl#=varptr(secl%(0) ) 

15 'The number of bytes to transfer (read-$1200,write-$1220) 

16 ' 

17 'and the command words for STEP-IN (with and without Update) 

18 ' 

19 numread=SH1200:numwrite=SH1220:stpi=&H49:stpiu=&H59 

20 ’ 

21 'We start in track 1 with Sector-1 and POKE longwords 

22 ' 

23 fdc%(15)=l:def seg=0 

24 ' 

25 copy: 

26 ?:fullw 2:clearw 2:gotoxy 0,1 

27 ?" Copy program for double-sided disks and 2 drives" 

28 ?:?:?:?" Insert source disk in drive A" 

29 ?:?" and destination disk in drive B." 

30 ?:?:?:?" c => copy : any other key => end program" 

31 if chr$(inp(2))<>"c" then end 

32 • 

33 init: 

34 clearw 2:gotoxy 0,2 

35 ' 

36 '-restore drive B and test write protect - 

37 ' 

38 fdc%(12)=11:fdc%(13)=4:call fdc# 

39 fdc%(12)=0:call fdc# 

40 if fdc%(18) < &HA7 then goto kopi 

41 ' 

42 ?" Diskette in drive B is write-protected! Please remove"; 

43 ?" write protection.":? 

44 ?" c => continue ; any other key => restart" 

45 fdc%(12)=11:fdc%(13)=0:call fdc# 

46 if chr$(inp(2))="c" then init 

47 goto copy 


372 






Abacus 


Atari ST Disk Drives Inside and Out 


48 ’ 

49 kopi: 

50 '-Drive A Restore 

51 fdc%(12)=11:fdc%(13)=2:call fdc# 

52 fdc%(12)=0:call fdc# 


53 ■ 

54 '-Copy track 0 through track 79 - 

55 ' 

56 for track = 0 to 79 : fdc%(16)=numread 

57 ' 

58 '-Read side A/0 and display status 


59 fdc%(12)=5:poke fdc#+56,secO#:call fdc# 

60 gotoxy 10,2:?"Track";track;"Reading side 0 

61 gosub checkstat 

62 ' 

63 '- Read side A/1 and display status - 

64 fdc%(12)=11:fdc%(13)=3:call fdc# 

65 fdc%(12)=5:poke fdc#+56,seel#:call fdc# 

66 gotoxy 10,2:?"Track";track;"Reading side 1 

67 gosub checkstat 

68 ' 

69 '- Drive A step-in without 'Update' — 

70 fdc%(12)=3:fdc%(4)=stpi:call fdc# 

71 ' 

72 '-Write side B/0 and display status 

73 fdc%(16)=numwrite 

74 fdc%(12)=ll:fdc%(13)=4:call fdc# 

75 fdc%(12)= 6 :poke fdc#+56,secO#:call fdc# 

76 gotoxy 10,4:?"track";track;"Write side 0 " 

77 gosub checkstat 

78 ' 

79 i-Write side B/l and display status 

80 fdc%(12)=11:fdc%(13)=5:call fdc# 

81 fdc%(12)= 6 :poke fdc#+56,seel#:call fdc# 

82 gotoxy 10,4:?"Track";track;"Writing side 1 

83 gosub checkstat 

84 ' 

85 '-Drive B step-in with pdate- 

86 fdc%( 12 )=3:fdc%(4)=stpiu:call fdc# 

87 • 

88 '-and select A/0 again- 

89 fdc%(12)=11:fdc%(13)=2:call fdc# 

90 ' 

91 next track 

92 ' 

93 fdc%(12)=11:fdc%(13)=0:call fdc# 

94 ?:?:?"Done ! .(r)estart or (e)nd ?" 


373 























Abacus 


Atari ST Disk Drives Inside and Out 


95 if chr$(inp(2))<>"r" then end 

96 goto copy 

97 .- 

98 checkstat: 

99 if fdc%(18)=&H80 and fdc%(19)=3 and fdc%(20)=0 then return 

100 gotoxy 0,7:?" FDC STATUS :$";hex$(fdc%(18)) 

101 ?" DMA STATUS : $";hex$(fdc%(19)) 

102 ?" #DMA BYTES :;hex$(fdc%(21)) 

103 ?" TIMEOUT :hex$(fdc%(20)):? 

104 ’ 

105 ?" Copy terminated because of an error." 

106 ?:?" Press a key..." 

107 fdc%(12)=11:fdc%(13)=0:call fdc# 

108 key=inp(2):goto copy 


8.3.4 Demo 3—Creating standard and foreign formats 


The following program, designed to create various formats on disks, 
illustrates another use of the FDC machine language routines. 

The program has two uses. The first shows how a track buffer (which is 
written to the disk by means of WRITE TRACK and represents the 
"format") is prepared, and the second formats disks so that they can be read 
and written by other computer systems (assuming that their drives are also 
controlled by a WD1772 or a compatible device). The reverse is also 
possible. A format may not satisfy the requirements of the FDC, which will 
refuse to transfer sectors in this format. The following warning should be 
kept in mind: 

IMPORTANT! Creating a format is a task which requires precise 
knowledge of the WRITE TRACK command. Parameters 
are to be changed only with the greatest of care. A number 
of things work, but not everything. In short: Read 
carefully the description of the FDC commands. There 
you will find information on what changes can be made to 
the individual components in the track. 

This program offers the following features: 

1) A track buffer, influenced by a number of parameters, can be 
prepared. To give you an overview of the values that are normally 


374 




Abacus 


Atari ST Disk Drives Inside and Out 


used, the parameters default to the values of the Atari format. The 
parameters can be reset to these values at any time. 

The buffer is large enough to hold all of the parameters entered in 
addition to the track format. Naturally, the prepared buffer cannot be 
complete. There are some values which differ from track to track or 
from side to side. For example, the track number is inserted as the 
track specification in the ID field. Such information must constantly 
be updated while a disk is being formatted. The necessary address in 
the ID fields are placed in the track buffer. 

2) A formatted buffer can be saved as a file on the disk so that you don't 
have to re-enter a set of values every time you want to format a disk 
in a special format. You can use this feature to create your own 
"format library" with standard and copy-protected formats. 

3) A format file that has been saved to disk can be loaded back into the 
buffer later. 

4) Naturally, it is also possible to format a disk. This formatting routine 
takes care of updating the track number in the ID fields. You can 
specify an offset which will be added to the track number. Generally, 
this is useful only for copy protection. 

io >*************************************************************** 

12 i***** Extended disk formatting A.S. (7/86) ***** 

14 i*************************************************************** 

16 dim fdc%(700) :fdc# =varptr(fdc%(0)) 

18 dim trk%(3200):trk# =varptr(trk%(0)) 

20 bload "a:fdcinter,b",fdc# 

22 def seg=0:poke fdc#+52,trk# 

24 i*************************************************************** 

26 gosub defaultRead standard values for ATARI-FORMAT 

28 menu: 

30 ?:fullw 2: clearw 2:gotoxy 0,0:width 80 

32 

34 ?" a) GAP1 change I" 

36 ?" b) GAP2 change I" 

38 ?" c) GAP3 (Part 1) change I" 

40 ?" d) GAP3 (Part 2) change I" 

42 ?" e) GAP4 change I" 

44 ?" f) DATA-FIELD change I" 

46 ?" g) SYNC-Bytes (for the ID-field) change 

48 ?" h) SYNC-Bytes (for the Data-field) change |" 

50 ?" i) DATA-ADDRESS-MARK change I" 


375 







Abacus 


Atari ST Disk Drives Inside and Out 


52 

? " 

j) 

START-SECTOR change 

1" 

54 

? " 

k) 

SECTOR-LENGTH (in ID-field) change 

1 " 

56 

? " 

1) 

RECORD-NUMBER change 

1" 

58 

?" 

m) 

GAP5 change 

1 " 

60 

62 


1 9 it 

l 9 ii. 



64 

?ll 

n) 

Prepare track-buffer 

II • 

r 

66 

?" 

q) 

Set values to ATARI-FORMAT " 


68 

?" 

o) 

Load track-buffer from disk 

it • 
r 

70 

? " 

r) 

Format diskette" 


72 

? " 

P) 

Save track-buffer as file 

ii • 

r 

74 

?M 

s) 

End" 



76 

78 for prm=0 to 15 Step 2 

80 gotoxy 40,prm/2:?"Number:";trk%(3150+prm);" " 

82 gotoxy 55,prm/2:?"Value:$ hex$(trk%(3151+prm));" ":next prm 

84 for prm=16 to 20 

86 gotoxy 55,prm-8:?"Value:$ hex$(trk%(3150+prm));" ":next prm 

88 

90 keypress: 

92 gotoxy 0,16:?spc(60):gotoxy 0,16:?" Which function?"; 

94 key=inp(2):if chr$(key)<"a" or chr$(key)>"s" then 94 
96 choose=key+l-asc("a") 

98 if choose=19 then end 

100 if choose<9 then goto twovalues 

102 if choose<14 then goto onevalue 

104 choose=choose-13: 

106 on choose gosub prepare,loadit,saveit,default,formatit 

108 goto menu 

110 

112 '=============== input number and value ====================== 

114 twovalues: 

116 gotoxy 0,16:?spc(60):gotoxy 0,16 

118 ?" >> chr$(key);" « Enter new value: ";:input amt$ 

120 if len(amt$)=0 then goto two 

122 trk%(3148+choose*2)=val(amt$):gotoxy 21,choose-1:?"Number: 

124 ?trk%(3148+choose*2);" 

126 two: 

128 gotoxy 0,16:?spc(60):gotoxy 0,16 

130 ?" >> ";chr$(key);" << Enter new value: ";:input w$ 

132 if len(w$)=0 then goto keypress 

134 trk%(3149+choose*2)=val(w$):gotoxy 30,choose-1:?"Value;$"; 

136 ?hex$(trk%(3149+choose*2));" ":goto keypress 
138 ’ 

140 '==================== input value ============================ 

142 onevalue: 

144 gotoxy 0,16:?spc(60):gotoxy 0,16 


376 











Abacus 


Atari ST Disk Drives Inside and Out 


146 ?" » chr$(key);" « Enter new value: ";:input w$ 

148 if len(w$)=0 then goto keypress 

150 trk% (3157+choose)=val(w$):gotoxy 30,choose-1:?"Value:$ 

152 ?hex$(trk%(3157+choose));" ":goto keypress 
154 

156 •==================== PREPARE TRACK BUFFER =======-============ 

158 prepare: 

160 clearw 2:gotoxy 12,0:?"Prepare track buffer ":? 

Ig2 - -Test entire length- 

164 complete=0 

166 for i=3152 to 3164 step 2 :complete=complete+trk%(i):next i 
168 complete=(complete+9)*trk%(3169)+trk%(3150) 

170 if complete <= 6234 then goto goahead 

172 if complete >6250 then ?:?:?" Track information too long":goto 
fail 

174 ?:?" There are only 6250-complete; 

176 ?" bytes remaining in the track sector.":?:?" Too small!" 


178 fail: 

180 ?:?" Please press a key...":key=inp(2) :return 

182 goahead: 

1 84 >-WRITE BUFFER- 

186 offset=l:?" Track offset (";trk%(3150);"Byte ) 

188 amount=trk%(3150):value=trk%(3151):gosub bufpoke:' GAP1 
190 for record = 1 to trk% (3169):?" Record:record 


192 amount=trk%(3152):value=trk%(3153):gosub bufpoke:' GAP2 
194 amount=trk%(3162):value=trk%(3163):gosub bufpoke:' SYNC 
196 def seg=offset:trk%(3170+record)=offset: 1 ID-Adr. merken 
198 poke trk#-l,SHfe:' 

200 poke trk#+2,record-l+trk%(3167):' 

202 poke trk#+3,trk%(3168):' 

204 poke trk#+4,&Hf7:offset=offset+6:' 

206 amount=trk%(3154):value=trk%(3155):gosub bufpoke:' 

208 amount=trk%(3156):value=trk%(3157):gosub bufpoke:' 

210 amount=trk%(3164):value=trk%(3165):gosub bufpoke:' 

212 def seg=offset:poke trk#-l,trk%(3166):' 

214 offset=offset+1 

216 amount=trk%(3160):value=trk%(3161):gosub bufpoke:' 

218 def seg=offset:poke trk#-l,&Hf7:offset=offset+1:' 

220 amount=trk%(3158):value=trk%(3159):gosub bufpoke:' 

222 next record 

224 ?" Track offset (";6250-offset;"Byte )" 

226 amount=6300-offset:value=trk%(3170):gosub bufpoke:' 

228 

230 ?:?:?" Buffer is ready!":pready=l:return 

232 

234 bufpoke: 

236 For i = 0 to amount-1:def seg=offset+i:poke trk#-l,value:next i 


ID-AM 

START-SECTOR 
SECTOR-LENGTH 
ID-CRC 
GAP 3 
GAP 3 
SYNC 
DAM 

SECTOR-DATA 
DATA-CRC 
GAP 4 


377 











Abacus 


Atari ST Disk Drives Inside and Out 


238 offset=offset+amount:return 

240 

242 '=============== STANDARD VALUES FOR ATARI FORMAT =============== 

244 default: 

246 restore 406:for i=3150 to 3170:read standard:trk%(1)=standard 

248 next i: pready=0:return 

250 

252 '=======’—======== WRITE TRACK BUFFER TO DISK ============== 

254 saveit: 

256 clearw 2:gotoxy 12,2:?"Write track buffer to disk":?:?:? 

258 if pready=l then goto speich2 

260 ?" Track buffer is still empty.Prepare the buffer before "; 

262 ?"saving!":?:?" Please press a key ...":key=inp(2):return 
264 saveit2: 

266 ?:?:?" Save buffer data as a disk file (y/n) ?":?:? 

268 if chr$(inp(2))<>"y" then return 

270 input " Please input filename for the format data:",file$ 

272 bsave file$,trk#,6402:return 
274 ' 

276 -================= LOAD TRACK BUFFER FROM DISK ================== 

278 loadit: 

280 clearw 2:gotoxy 12,2:?"Load track buffer from disk":?:?:? 

282 ? " What program name is the format"; 

284 ? "saved under? ":?:input file$ 

286 open"R",1,file$,1:test=lof(1):close 1 

288 if test=6402 then bload file$,trk#:pready=l:return 

290 ?:?:? " This is no data file !!! Please press a key...." 

292 a=inp(2):return 

294 '==—================= FORMAT A DISKETTE ==================== 

296 formatit: 

298 clearw 2:gotoxy 12,2:?"Format a diskette":?:?:? 

300 if pready=l then goto frmt2 

302 ?" Track buffer is still empty. Please prepare the track 
304 ?"first!":?:?" Please press a key":key=inp(2):return 
306 frmt2: 

308 ?" Format a diskette (y/n) ?" 

310 if chr$(inp(2))<>"y" then return 
312 

314 ?:?:?" Please put the disk to be formatted in Drive A.":? 

316 input " From which track?",a$:a=val(a$):if a<0 or a>82 then 316 
318 input " To which track?",a$:b=val(a $) 

320 if b<0 or b>82 then 318:if b<a then 316 

322 ?:?"Which offset should contain the track numbers in the 
324 ?"ID fields?":?" A value between 0 and ";244-b;" is valid." 

326 ?" Normal offset is » 0 <<":? 

328 input " Offset? ",a$:if val(a$)<0 or val(a$)>244-b then 328 
330 off=val(a$) 


378 




















Abacus 


Atari ST Disk Drives Inside and Out 


332 ?:?" Which side should be formatted?" 

334 ?:?" (0)=Front or (l)=Back" 

336 key=inp(2) 

338 if chr$(key)="0" then drive=2:goto format 

340 if chr$(key)="1" then drive=3:goto format 

342 goto 336 
344 format: 

346 ?:?" Last chance to abort! (f)ormat (q)uit" 

348 key=inp(2):if chr$(key)="q" then goto formatit 
350 if chr$(key)<>"f" then 348 

352 '-formatit - 

354 fdc%(12)=11:fdc%(13)=drive:call fdc#: 1 Select drive 
356 again: 

358 fdc%(12)=0:call fdc#:'RESTORE 
360 if fdc%(18)<&Ha7 then goto sek 

362 ?:?" *** ERROR! The diskette is write-protected!" 

364 ?:?" (r)epeat or (q)uit ?" 

366 key=inp(2):if chr$(key)="q" then goto frmt 

368 if chr$(key)="f" then fdc%(12)=10:call fdc#:goto again 

370 goto 366 

372 sek: 

374 fdc%(12)=1:fdc%(14)=a:call fdc# :' R/W-head at starting track 
376 

378 fdc%(16)=6400 

380 for track=a to b 

382 for record=l to trk%(3169) 

384 def seg=trk%(3170+record):poke trk#,track+off 

386 poke trk#+l,drive-2:next record 

388 

390 fdc%(12)=8:call fdc# :' WRITE-TRACK 

392 if fdc%(18)OSH80 or fdc%(19)<>3 then ?" *** Error! Track:";track 
394 fdc%(12)=3:call fdc# :' STEP-IN 
396 next track 

398 frmt: 

400 fdc%(12)=11:fdc%(13)=0:call fdc#:goto formatit:'de-select 
402 end 

404 '-data for ATARI-FORMAT- 

406 data 60,78,12,0,22,78,12,0,40,78,512,229,3,245,3,245,251,1,2,9,78 


379 








Abacus 


Atari ST Disk Drives Inside and Out 


8.4 Creating BASIC loaders 


This section deals only indirectly with the disk drive. It involves a simple 
but very useful tool. In part it is intended as an answer to all the "hackers" 
who are always ready with a machine language solution to everything. 
Programming doesn't always have to involve a complete public domain 
program ready to offer to the masses. Often all somebody needs is just a 
little bit of help. But read for yourself. 

A large number of programming problems can be solved with a BASIC 
program—easily and quickly. This language has its limitations when high 
speed is required, however. The small details usually prevent a good idea 
from being realized in BASIC. When the problem involves creating 
animated graphics for a game, the BASIC programmer has to pass. On the 
other hand, even a comprehensive database manager can be written in 
BASIC, but we still run into problems when it comes to sorting large 
quantities of data. 

The point is this: There are assembly language programmers among us who 
write small, useful machine language routines. These same people also 
write BASIC programs. The hindrances of BASIC don't seem to exist for 
them. The reason for this is quite clear; the parts of the program which take 
too much time for the BASIC interpreter are converted into machine 
language. These routines are then called with a simple "call" instruction. 

It would be nice if these routines were also available for those of us who 
don't have an assembler. A BASIC program must be written which contains 
the data for the machine language routine and which then either pokes this 
data into memory or creates a disk file of the routine to be loaded later with 
BLOAD. We wrote this program to make these subroutines available to 
straight BASIC programmers. 

The BASIC program shown here performs an assembler-to-BASIC-to- 
assembler conversion. After the program is started, it asks for the name of 
the file to be converted. Following this, two more filenames must be 
entered: 

1. The name of the BASIC loader to be created. This program will most 
often be distributed to others in the form of a listing. A checksum is 
also included to try to reduce the number of typing errors which often 
occur when entering a large number of data statements. 


380 




Abacus 


Atari ST Disk Drives Inside and Out 


2. The name of the file which the BASIC loader should later create. The 
loader tests to see if the checksum of the data read matches the 
checksum in the data. If this is the case, a file will be written to the 
disk which is identical to the original. 

10 '************************************************************* 

20 i*********** Data-Maker A.S. 10/86 *************** 

30 i************************************************************* 

40 

50 'Creates a BASIC program out of any file. This can be started 

60 'later with 'RUN', and will write a file identical to the other 

70 'program. 

80 ' 

90 '************************************************************* 

100 

110 ?:fullw 2:clearw 2:gotoxy 0,0 

120 input "Which file do you want converted to DATA"; prg$ 

130 ' 

140 open"R",#1,prg$,1:bytes=lof(1):close: feldlen=cint(bytes/2-1) 

150 ?"INFO —>> ";prg$;" << takes up ";bytes;" bytes" 

160 ?:? 

170 

180 input "What do you want to call the output file";bas$:?:? 

190 

200 ?"A loader will be integrated as >> ";bas$;" <<, which" 

210 ?"will be the equivalent of the input file" 

220 ?">> ";prg$;" << but made of DATA statements.":?:?:? 

230 input "Please input the final filenamemake$ 

240 ?;?"*************************************************************!, 

260 ?"The program will be loaded intop 

270 ?"an integer array (c%) with ";feldlen;" as the array length." 

280 dim c%(feldlen) 

290 ? 

300 ?"The input file >> ";prg$;" << will be loaded at varptr(c%(0))." 

310 bload prg$,varptr(c%(0)) 

320 

330 ?:?"The output file » ";bas$;" << is now being opened." 

340 open"0",1,bas$ 

350 

360 ?"The contents of the c%-array will now" 

370 ?"be written in to this file in DATA form." 

380 ?"Working." 

390 

400 check#=0:z=0:zl=100 

410 

420 if z mod 8 =0 then print #l:print #1,str$ (zl);" DATA ";:zl=zl+l 
430 


381 





Abacus 


Atari ST Disk Drives Inside and Out 


440 print #1,right$("0000"+hex$(c%(z) ) , 4) ; 

450 ' 

460 check#=check#+c%(z):z=z+l 

470 if z=feldlen+l then 510 

480 if z mod 8 <> 0 then print #1,","; 

490 goto 420 
500 

510 ?:?:?"Loader program now being appended....” 

520 ' 

530 print #1 

540 print #1,str$(10);" ********** File-Maker A.S. ****** 

550 print #1,str$ (15);" 

560 print #1,str$(20);" ?:fullw 2:clearw 2:gotoxy 0,0" 

570 print #1,str$(25);" ? ";chr$(34);"File » ";make$; 

580 print #1," << now being created";chr$(34) 

590 ' 

600 print #1,str$(30);" dim c%(";str$(feidlen);"):cs#=0" 

610 

620 print #1,str$(35);" for i=0 to str$(feidlen) 

630 

640 print #1,str$(40);" read a$: 

c%(i)=val(";chr$(34);"&H";chr$(34);"+a$)" 

650 

660 print #1,str$(45);" check#=check#+(c%(i))" 

670 

680 print #1,str$ (50);" next i" 

690 

700 print #1,str$(55);" if check#=";str$(check#);" then ";str$(70) 
710 

720 print #1,str$(60);" ?";chr$(34);"Can't go any farther;"; 

730 print #1,"something wrong with the DATA.";chr$(34) 

740 print #1,str$(65);" goto 80" 

750 ' 

760 print #1, str$(70) ; " bsave";chr$(34);make$;chr$(34) ; 

",varptr(c%(0)),"; 

770 print #1,str$(bytes) 

780 ' 

790 print #1, str$(75);" ? ";chr$(34);"The program >> ";make$; 

800 print #1," << is now written .";chr$ (34) 

810 

820 print #1,str$(80);" ?:?";chr$(34);"Please press a key"; 
chr$(34)";"; 

830 print #1, ":a=inp(2):end" 

840 print #1,str$(85);" ' " 

850 print #1,str$(90);" ********** DATA for ";make$;" **********" 
860 print #1,str$ (95);" >" 

870 ’ 


382 






Abacus 


Atari ST Disk Drives Inside and Out 


880 ?"...closing the output file..." 

890 close #1 
900 ’ 

910 ?:?"The program >> ";bas$;" >> is ready." 

920 ?:?"Please press a key":a=inp(2):end 


383 












Abacus 


Atari ST Disk Drives Inside and Out 


Appendix: ASCII character set 


The following table illustrates the printable ASCII character set of the Atari 
ST. The corresponding numeric values (ASCII values, which can be 
conveyed by the ASC ("") function in BASIC) can be computed by 
combining the hexadecimal number on the top border with the number on 
the left border. For example, the ASCII value of the "A" character is $41. 

You can print this table out on your own system with the following GFA 
BASIC program and a printer: 

Cls 

For 1=0 To 15 

Print At (1*3+7,3);Hex$(I) 

Print At (4,1 + 4);Hex$(I) 

Deftext 1,0,0,13 
For J=0 To 15 

Text 92,56,"SPC" 

Next J 
Next I 

Deftext 1,0,0,4 
For 1=1 To 18 

Draw 18,1*16+15 To 424,1*16+15 
Draw 1*24-7,31 To 1*24-7,303 
Next I 

Draw 17,31 To 40,47 
Repeat 

Until Mousek 
Edit 


387 


Atari ST Disk Drives Inside and Out 
















































































































































Abacus 


Atari ST Disk Drives Inside and Out 


Index 


ALLDIR. TOS program 
Address mark detector 
Arithmetic logic unit (ALU) 

ASCII 

Assembler compatibility 
Attribute byte 
BASIC 

BASIC loaders 

BASIC-TOS interface program 
BASIC/FDC interface —see FDCINTER program 
bigfmt program 
BIOS parameter block (BPB) 

Boot sector 

BPB analysis program (BPBANA. TOS) 

C (language) 

CLOSE (GEMDOS) 

Cluster 

Command descriptor block 
CREATE (GEMDOS) 

Cyclic redundancy check (CRC) 

Data field 

Data-Maker program 
database program 
Direct Memory Access (DMA) 

Directory 65-69,153,168 

Directory reader program —see read directory 
Disk copying 
Disk drives 

disk editor program 
CLUSTER menu 
FORMAT menu 
GAP menu routines 
main menu 
OPTIONS menu 
SECTOR menu 
TRACK menu 
TRACK with SYNCS menu 
Disk monitor—see disk editor program 
Disk/RAM disk copying 


168-175 

92-93,104 

92 

8,12,15,17,387-388 

318 

312 

8,14-18 

321-383 

323-324 

50-58 

47,58-59,64,202-205 

45,47-50,56,58 

59-64 

24-31 

12 

45-46,58,65,66,68,69 

141-158 

11 

91-92 

118-119 

381-383 

35-38 

79-80,144-147 

-172,309-312,325-328 

program 

370-374 

77-197 

210-317 

278-292,306 

293-297,307 

297-303,307-308 

215-255,303-304 

256-261,308 

305-306 

262-269,304-305 

269-278,305 

193-198 


389 


Abacus 


Atari ST Disk Drives Inside and Out 


Extended disk format program—see bigfmt program 

Field 9,39 


FDCINTER program 
File Allocation Table (FAT) 

File extension 
File handle 
Files 

random-access 

sequential 

Floppy disk controller (FDC) 
Folder 

FORCE INTERRUPT 
Foreign formats 
Format 

Formatting programs 

FORTRAN 

GAP 

GEMDOS 

GETBPB 

GET_TIME in BASIC program 
Hard disk 

hard disk access programs 
Hard disk controller (HDC) 


342-370 

46,48,68-69,313-314 

7-8,11,39 

11 

7-34 

9-10,16-18,22-23,29-31,33-34,202 
9,15-16,19-22,27-28,32-33 
80-118,342,361-363 
65,68,168,315 
90,96,99,106,126,360 
316-317,374-379 
45-47 
50-63,331-334 
11,32-34 
117-118 
11-13,24,56,143 
47-50,58-64,204-205 
340-341 
137-175 
144-146,153-157 
139-167 


Hard disk directory printout—see ALLDIR. TOS 
ID field—see index field 


Index field 


119-121 


Interleave 
Logical sector 
LSEEK (GEMDOS) 

Magic number 
MS-DOS 
Non-Atari format 
OPEN (GEMDOS) 

Partition 

partition analyzer program 
Pascal 

Physical sector 
Program header 
RAM disk 
READ (GEMDOS) 

READ ADDRESS 


149,167,207 

310-311 

13 

47 

48 

316-317,374-379 

11 

73-74,153,157-167 

158-167 

11,19-23 

310-311 

70-72 

179-192 

12 

89-90,96,112-113,124,130,360 


Read clock time program 339-341 

READ DATA 89 


390 


Abacus 


Atari ST Disk Drives Inside and Out 


read directory program 
read/write sector program 
READ SECTOR 
READ TRACK 
Record 

Relocation table 
RESTORE 
Searching data 
Sector 
SEEK 

SETDTA (GEMDOS) 

SFIRST (GEMDOS) 

SNEXT (GEMDOS) 

Shugart interface 
Sorting data 
Status register 
STEP 
STEP IN 
STEP OUT 

Subdirectories —see folder 
Supervisor mode 
Synchronization bytes 
Track 

Tramiel Operating System (TOS) 
User mode 
WRITE (GEMDOS) 

Write precompensation 
WRITE SECTOR 
WRITE TRACK 
XBIOS 


325-328 

328-329 

105-107,110,361 

81,113-115,125,130 

9,39 

72-73 

89,96,100,128,147,148,204,205 

40,318,334-336 

45-50,78 

13,27,29,30,86,96,100,128, 151-152 

13 

13,67 

13,67 

131 

40,336-338 

84,87,90,101,112,126-130 

101,128,202 

101,128 

101,128 

143-144 

78,116,118 

10,45-46 

202-210 

144 

12 

95-96,344 

107,111 

81,115-118,123,130 

80,202,205-210 


391 
























Optional Diskette 



For your convenience, the program listings contained in this book are 
available on an SF354 formatted floppy disk. You should order the diskette 
if you want to use the programs, but don't want to type them in from the 
listings in the book. 

All programs on the diskette have been fully tested. You can change the 
programs for your particular needs. The diskette is available for $14.95 plus 
$2.00 ($5.00 foreign) for postage and handling. 

When ordering, please give your name and shipping address. Enclose a 
check, money order or credit card information. Mail your order to: 

Abacus, Inc. 

5370 52nd Street SE 
Grand Rapids MI 49508 


Or for fast service, call ( 616 ) 698-0330 













GEM Programmer's Reference 

Atari ST GEM Programmer's Reference is an indispensable guide if you're a 
serious ST programmer needing detailed information on GEM. Atari ST 
GEM Programmer's Reference is written especially for the ST and has an 
easy-to-follow format. The GEM routines are explained with examples 
written in both C and 68000 assembly language. 

Topics include: 

• Overview of GEM: VDI, AES, 

GDOS, GIOS 

• Intro to programming with GEM 

• The ST Development System 

• Using the Editor, C-compiler, 

Assembler and Linker 

• Inside GEM: programming the Virtual 
Device Interface (VDI) 

• Inside GEM: programming the 
Application Environment Services (AES) 

GEM Programmers Reference is a complete programming handbook for all 
ST users. 412 pages. Optional diskette available. 


mm 

-V- 


GEM Programmer's Reference 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 


A complete guide to < 
programming the ST using the 
Graphics Environment 

Manager 




"Anyone interested in learning how 
to manipulate the VDI or the AES 
will want to have this book at their 
fingertips..." 

—Richard Kaller 
ST Applications 

"Despite its title, the Atari ST GEM 
Programmer's Reference is really a 
complete programming handbook 
for the ST." 

—Donald Evan Crabb 
Byte 


Optional Program Diskettes 

Don't forget optional program diskettes are available for all the books 
in the Atari ST Reference Library (except where noted). These optional 
diskettes contain all the program listings printed in the books, and will 
save you hours of tedious typing. 

Each optional diskette: $14.95 



Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOOO are trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 
































Selected Books from our 


Machine Language 

Atari ST Machine Language is the complete introduction to the high-speed 
world of 68000 machine language on the Atari ST. Atari ST Machine 
Language is required reading if you're interested in getting out the full 
potential built into the spectacular MC68000 microprocessor used in the 
Atari ST line of computers. Topics include: 

• Logical operations and bit manipulations 

• 68000 register structure and data organization 

• Fundamentals of assembly language programming 

• Operating system and programs 

• Solutions to typical problems 

• Program development 

• Step by step programming 

■ Program and memory structure 

Atari ST Machine Language also contains many simple programs that 
progressively teach the fundamentals of programming in 68000 machine 
language. 280 pages. Optional diskette available. 


Reference 

Library 



Atari ST Machine Language 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 


Tricks & Tips 


Atari ST Tricks & Tips is a fantastic collection of ST programming tools 
and techniques that every ST user will find valuable. Teaches you how to 
define BASIC, assembler and C programs with the advanced programming 
techniques found exclusively in Atari ST Tricks & Tips. Topics include: 

• Special ST BASIC commands 

■ "Safe" locations for M/L programs 

• Using the VDISYS commands 

• Mastering powerful GEM applications 

• Producing fantastic graphics 

• Building a RSC file 

Program listings included in Atari ST Tricks & Tips: 

• Super-fast RAM disk 

• Time-saving printspooler 

• Color print hardcopy 

■ Plotter output hardcopy 

• Auto-starting TOS application 

• Creating accessories 

Plus much more—and all programs are included in the price of the book! 
Full four-color plates in appendix show you the STs graphic capabilities. 
Fully indexed. 260 pages. 



Atari ST Tricks & Tips 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 


".. .this book a best-seller and I can 
understand why." 

—Pamela Rice Frank 
Current Notes 


Atari ST, 520ST, 1040ST, TOS, ST BASIC arai ST LOGO arc trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 





Selected Books from our 


Graphics & Sound 

Atari ST Graphics & Sound teaches the ST user how to create graphics and 
make full use of the built-in sound capabilities of the Atari ST. Example 
programs listed in Atari ST Graphics & Sound are written in BASIC, C, 
LOGO and Modula-2. Topics include: 


Reference 

Library 


Mirror and rotation 
Graphics under GEM 
Coordinate transformations 
Raster and vector graphics 
Principles of music synthesis 
Sound chip 

Plotting math functions in 2D & 3D 


Moire patterns 
Bar and pie charts 
Fractals 

Waveform generation 

The ST as a synthesizer 

MIDI control of musical devices 


Atari ST Graphics & Sound is a must for the ST owner who wants an in- 
depth look at creating sophisicated graphics and surprising music and sound 
with the ST. 255 pages. Optional diskette contains dozens of graphics and 
sound programs. 


Atari ST Graphics & Sound 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 



LOGO User’s Guide 

ST LOGO was designed specifically to take full advantage of the Atari STs 
fantastic graphic capabilities. LOGO'S English-like words may be extra¬ 
ordinarily easy to learn, yet LOGO programs are actually built along the 
lines of advanced artificial intelligence languages like LISP. Atari ST 
LOGO User's Guide gently introduces the reader to the fundamentals of ST 
LOGO with numerous examples, dozens of actual screen illustrations and 
exercises that optimize the STs features. Then it moves on to work with 
the more advanced features LOGO has to offer—readers will soon be 
programming highly complex tasks on their STs under LOGO. Topics 
covered: 

• Thorough introduction to GEM, windows, and the mouse 

• Randomizing and repetition 

• Programming with recursion 

• LOGO words & lists 

• Data structures in LOGO 

• Error output 

• Computing with LOGO 

■ ST LOGO system, input and output commands 

• Programs as lists 

Atari ST LOGO User's Guide covers everything your customers need to 
know about this acclaimed teaching and graphics language. 370 pages. 


LOGO USER’S GUIDE 

The definitive guide to using ST LOGO 



Atari ST LOGO User's Guide 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 


" A worthwhile addition to your 
reference library... contains many 
examples & demonstration programs 
in the LOGO language." 

—Brace Laubenheimer 
Computer Shopper 

"For those folks who have been 
waiting for an excuse to start play¬ 
ing with LOGO, this may be it!" 

—Steve Tearle 

Atari Journal 


Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 















Selected Books from our 


Peeks & Pokes 

PEEK and POKE commands act as bridges between the user and the Atari 
ST's operating system through ST BASIC. Atari ST Peeks & Pokes 
enhances the user's knowledge of the ST and programs with numerous 
PEEK and POKE examples. 

Atari ST Peeks & Pokes clearly explains a number of the most important 
PEEKS and POKES and their application to common programming 
problems. At the same time, this book gives you an excellent look at the 
architecture and operation of the exciting Atari ST. Topics include: 


• The ST's configuration and interfaces 

• The "intelligent" keyboard 

• The mouse as a paintbrush 

• Pointer and stack 

• Customizing the desktop 

• Important PEEKs & POKEs 

• Making your own fill patterns 

• ST communications 

• Direct disk access 

• Internal memory configuration 

Atari ST Peeks & Pokes unlocks the secrets hidden within the ST with an 
excellent collection of "quick hitters" and information. 200 pages. 


Reference 

Library 


Atari ST Peeks & Pokes 
Optional Diskette 


Suggested Retail Price: $16.95 
Suggested Retail Price: $14.95 


m 

1 

HUM 

p< 


jks & Pokes 

The authoritative insider's guide 



BASIC Training Guide 

Atari ST BASIC Training Guide for the Atari ST is a functional, 
educational and well-written introduction to ST BASIC. Quickly teaches 
you the fundamentals of programming with an introduction to program 
analysis, problem analysis, algorithms, and BASIC commands. This 
systematic book makes learning programming in the popular BASIC 
language quicker and easier than ever before. 

Quizzes throughout the book help you leam to "think in BASIC" while 
you'r getting a practical grounding in the language. Topics include: 

• Data flow and program flowcharts 

• Advanced programming techniques 

• Menus 

• Multi-dimensional arrays 

• Sort routines 

• File management 

• BASIC under GEM 

In addition, Atari ST BASIC Training Guide also contains advanced 
programming techniques if you already know ST BASIC. 312 pages. 



BASIC Training Guide Suggested Retail Price: $16.95 —uavu 

Optional Diskette Suggested Retail Price: $14.95 

Anri ST, 520ST, 1040ST, TOS, ST BASIC anl ST LOGO are trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 


"The Atari ST BASIC Training 
Guide is a first-class text for ST 
BASIC users. It is clear, thorough, 
well-written and remarkably free of 
errors and typos... does a good jog 
of introducing the user to ST 
BASIC programming fundamentals. 
It also provides a valuable reference 
section for the more advanced user." 

—David Plotkin 
Antic 




























Introduction to MIDI Programming 

The digital music synthesizer is the musical instrument of the 80s. You 
can now buy synthesizers for under $1000 (as low as $250), play at least 
four voices at a time, and they can be connected to home computers through 
the Musical Instrument Digital Interface (MIDI) for computer control. The 
Atari ST is ideal for MIDI interfacing, since it has a built-in MIDI port. 
This means it's ready to hook up to any digital electronic musical 
instrument equipped with MIDI ports. 

ST Introduction to MIDI Programming gives you the groundwork for 
discovering the infinite musical possibilities of the Atari STs MIDI 
interface and your synthesizer. Topics include: 

• Introduction to MIDI programming 

• MIDI STANDARD and MIDI LANGUAGE 

• Programming your synthesizer 

• How to buy MIDI software 

• Using the extended BIOS 

• Source code from Xlent Software's ST 
MUSIC BOX© AUTO-PLAYER program 

• C source codes for many programs and functions 

Essential reading for anyone who uses the STs MIDI port. 256 pages. 

Introduction to MIDI programming Suggested Retail Price: $19.95 
Optional Diskette Suggested Retail Price: $14.95 


BASIC to C 

Atari ST BASIC to C was written expressly for those of you who've 
learned the essentials of ST BASIC, but are hesitant to try another 
language. This excellent book quickly takes you beyond the BASICS and 
teaches how to program in the C language—the language of choice for 
thousands of advanced program developers. Atari ST BASIC to C places 
simple BASIC programs and their equivalents in C code side-by-side, with 
clearly-written comparisons between the two languages. Now you can learn 
the groundwork for C programming in only one day ! Topics covered: 

• Development, applications and the benefits of C 

• Functions and text output 

• Program format 

• Loops and comments 

• Data input 

• Arithmetic in C 

• Control structures 

• Data types in C 

• C pointers and arrays 

• Common errors made by BASIC programmers 

Atari ST BASIC to C skillfully guides the BASIC programmer through the 
necessary steps for programming in the C language. An essential addition to 
the libraries of all ST users. 


Explore the infinite electronic 
musical capabilities of the ST 




Abacus Hjll Software 



Atari ST BASIC to C 
Optional Diskette 


Suggested Retail Price: $19.95 
Suggested Retail Price: $14.95 


"Imagine—if someone took all of 
the BASIC commands that you 
knew and loved so well, and showed 
how those commands would look 
and work in C...in a step-by-step, 
logical sequence with lots of 
examples — wouldn't that be nice? 
Well that's exactly what Abacus had 
Mr. Hartwig do, and it's very 
effective. This book creates an 
effective bridge between ST BASIC 
and the C programming language." 

—David M. Pochron 
The Atari Journal 


Atari ST, 520ST, 1040ST, TOS, ST BASIC end ST LOGO ire trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 















Selected Books from our 


3D Graphics 

Teaches how to create impressive, lightning-fast three-dimensional graphics 
on the Atari ST in 68000 machine language. Atari ST 3D Graphics covers 
introductory concepts and background materials, graphic animation, using 
the assembler and much more. 

Learn real-time animation with dozens of graphic routines. 3D Graphics is 
an amazing book for all programmers interested in advanced level graphics. 


Reference 

Library 


Some of the topics covered include: 

• Mathematical basis for 3D graphics 

• Coordinate systems 

• Scaling the axis 

• Two- and three-dimensional 
transformations 

• Hidden lines & surfaces 

• Data structure for 3D objects 


■ Object animation 

■ Spatial projection 

1 Rotation of objects 

■ Light and shadows 

■ Introduction to 3D computer-aided 
design (CAD) 


A must for all serious ST programmers. Atari ST 3D Graphics includes 
complete listings for a fascinating 3D pattern-maker and animator. 351 
pages. 

Atari ST 3D Graphics Suggested Retail Price: $24.95 

Optional Diskette Suggested Retail Price: $14.95 


ST Disk Drives: Inside and Out 

The latest title in the widely-acclaimed Abacus Atari ST Reference Library 
is the exclusive Atari ST Disk Drives: Inside and Out. This outstanding 
technical reference is Ihs definitive source of information for the ST disk 
drives—it thoroughly discusses the floppy disk, the hard disk and RAM disk 
from both a programming and a technical perspective. In addition, the reader 
will find several full-length utilities and programming tools that enables 
him to further explore the ST disk drives' operations and capabilities. 
Topics include: 


Information of sequential and random 

access file structures 

Access to data files from BASIC, 

Pascal, C, and FORTRAN 

Data structures and management 

The boot sector and BIOS parameter 

bloc (BPB) 

The directory and File Allocation 
Table (FAT) 


Relocation table 
Hard disk format 
Details of drive construction: 
(DMA chip, disk controller, 
connector 

layout, and organization, etc. 
Command description, status 
interpretation, floppy interface, 
hard disk partition analyzer 


ST Disk Drives: Inside and Out 
Optional Diskette 


Suggested Retail Price: $24.95 
Suggested Retail Price: $14.95 



3D GRAPHICS 
PROGRAMMING 



The programs are clearly printed, 
well commented, planned in a 
sensible modular fashion, and 
contain many invaluable assembly- 
language 'tips and tricks.' And they 
work. ST programmers are fortunate 
to have this book." 

—Douglas Weir 

ST-Log 


ST DISK DRIVES 


InsideN^ 
and Out^ 


Atari ST Disk Drives: Inside and Out is literally packed with utility 
programs. The book includes a complete listing for an easy-to-use RAM 
disk, BASIC/TOS interface, BASIC/FDC interface, BASIC loaders, Floppy- 
to-RAM disk copy, creating standard and foreign formats, and many more 
timesaving programs. Available April '87. 


Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks of Atari Corp. GEM is a registered trademark of Digital Research Inc. 

























Editor Search Block Hell 


Desk rile Rssenbler Debus 


kssetibii 


MlndOM Issenblcr UlodOM 


Desk Elio Assembler Debugger Editor Search Block Table 


Debugger^ 


] C^ 888BBB0 B , SSP 

100006 G82D0004 ORi”b $ » 

108800 05000004 MOVEP.l 

1B80BE 0508 BSET Dt 

100010 68B4BADA ORI.B t 

100014 G0040B2C ORI.B ‘ 

1B801B 00040838 ORI.B » 

10001C B0040B44 ORI.B < 

_JOBO20 B0B4BB5B ORI.B » 

ExetUttJJfOflrcn BBBU24 0OB4U5I ORI.B » 

=> erase 990028 BBFC DC.H $F 

^SfS'S^-rJUJSaS 000020 5C4B SUB.U f 

Relocate BB0B2C 0BOOCRC4 ORI.B t 


iloaie site 
JBeZBEnul 


iiurjuirjfi 

Haitebie 


6j|HjLjcrc_ 


/ SiiPN rcilsicr 
tiex_HunBrJc.-OU.toui 


Search 


Pebuqaer Editor Search Block Help 


628551 


Source text:# 
Object code:B 


ILOBEL TOSXTOS.L 
GEM.IHIT 

FORFLAIERT »1,RLRRHTEXT,D3 
FORK.ERROR 03,03 
GEM.EXIT 
GOTO 

ILfiRMTEXT:OC.8 "tilCThisIls|an 


AssemPro 

Machine language development system 
for the Atari ST 


Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks or Atari Corp. 
GEM is a registered trademark of Digital Research Inc. 


AssemPro is completely GEM-based—this makes it 
easy to use. The powerful integrated editor is a breeze to 
use and even has helpful search, replace, block, 
upper/lower case conversion functions and user definable 
function keys. AssemPro's extensive help menus 
summarizes hundreds of pages of reference material. 


Full screen editor with dozens of powerful features 
Fast 68000 macro assembler assembles to disk or 
memory 

Powerful debugger with single-step, breakpoint, 
68020 emulator, more 

Helpful tools such as disassembler and reassembler 
Includes comprehensive 175-page manual 


"...I wish I had (AssemPro) a year and a half ago... it 
could have saved me hours and hours and hours." 

—Kurt Madden 
ST World 


"The whole system is well designed and makes the rapid 
development of 68000 assembler programs very easy." 

—Jeff Lewis 

Input 


The fast macro assembler assembles object code to 
either disk or memory. If it finds an error, it lets you 
correct it (if possible) and continue. This feature alone 
can save the programmer coundess hours of debugging. 


The debugger is a pleasure to work with. It features 
single-step, breakpoint, disassembly, reassembly and 
68020 emulation. It lets users thoroughly and 
conveniently test their programs immediately after 
assembly. 


AssemPro Features: 


Suggested retail price: $59.95 


AssemPro is a complete machine language development 
package for the Atari ST. It offers the user a single, 
comprehensive package for writing high speed ST 
programs in machine language, all at a very reasonable 


AssemPro 


price. 


ITOR 


ON [TOR 


^EZ^BL^R 


EBUGGE 


I Flic nane outout 
/ Ootlnlzt backward Bcc 
t Flag undef. variables 
Listing 
Synbol tabic 
Error flic ! 

/ PC-ralatlva 
Relocatable 
Original lint 


Selected Abacus Products for the 


MMHBiia 














Selected Abacus Products for the 



Chartpak ST 

Professional-quality charts and graphs 
on the Atari ST 


In the past few years, Roy Wainwright has earned a 
deserved reputation as a topnotch software author. 
Chartpak ST may well be his best work yet Chartpak 
ST combines the features of his Chartpak programs for 
Commodore computers with the efficiency and power of 
GEM on the Atari ST. 

Chartpak ST is a versatile package for the ST that lets 
the user make professional quality charts and graphs 
fast . Since it takes advantage of the STs GEM 
functions, Chartpak ST combines speed and ease of use 
that was unimaginable til now. 

The user first inputs, saves and recalls his data using 
Chartpak ST's menus, then defines the data positioning, 
scaling and labels. Chartpak ST also has routines for 
standard deviation, least squares and averaging if they are 
needed. Then, with a single command, your chart is 
drawn instantly in any of 8 different formats—and the 
user can change the format or resize it immediately to 
draw a different type of chart. 

In addition to direct data input, Chartpak ST interfaces 
with ST spreadsheet programs spreadsheet programs 
(such as PowerLedger ST). Artwork can be imported 
from PaintPro ST or DEGAS. Hardcopy of the finshed 
graphic can be sent most dot-matrix printers. The results 
on both screen and paper are documents of truly 
professional quality. 

Your customers will be amazed by the versatile, 
powerful graphing and charting capabilities of Chartpak 
ST . 

Chartpak ST works with Atari ST systems with one or 
more single- or double-sided disk drives. Works with 
either monochrome or color ST monitors. PWorks with 
most popular dot-matrix printers (optional). 

Chartpak ST Suggested Retail Price: $49.95 



filari Stock Performance 

—flt ' H' W First Jij is pitlic • 11/87/86 


[p —=fltiri Hi|k Price 


SilU Hat is Itisl senre tt|itssin 
Dislti Hits ire I slJ Jt till in lilts 



' IB 

jiiumsfjiiiiini 


iii 

ill 

j S 

2/1/87 RCV 




ificiiUDiwan-ii 



7/11/17 


























DataRetrieve 

(formerly FilePro ST) 

Database management package 
for the Atari ST 


"DataRetrieve is the most versatile, and yet simple, 
data base manager available for the Atari 520ST/1040ST 
on the market to date." 

—Bruce Mittleman 

Atari Journal 

DataRetrieve is one of Abacus' best-selling software 
packages for the Atari ST computers—it's received 
highest ratings from many leading computer magazines. 
DataRetrieve is perfect for your customers who need a 
powerful, yet easy to use database system at a moderate 
price of $49.95. 

DataRetrieve's drop-down menus let the user quickly and 
easily define a file and enter information through screen 
templates. But even though it's easy to use, 
DataRetrieve is also powerful. DataRetrieve has fast 
search and sorting capabilities, a capacity of up to 
64,000 records, and allows numeric values with up to 
15 significant digits. DataRetrieve lets the user access 
data from up to four files simultaneously, indexes up to 
20 different fields per file, supports multiple files, and 
has an integral editor for complete reporting capabilities. 

DataRetrieve's screen templates are paintable for 
enhanced appearance on the screen and when printed, and 
data items may be displayed in multiple type styles and 
font sizes. 

The package includes six predefined databases for 
mailing list, record/video albums, stamp and coin 
collection, recipes, home inventory and auto 
maintenance that users can customize to their own 
requirements. The templates may be printed on Rolodex 
cards, as well as 3 x 5 and 4x5 index cards. 
DataRetrieve's built-in RAM disks support lightning- 
fast operation on the 1040ST. DataRetrieve interfaces to 
TextPro files, features easy printer control, many help 
screens, and a complete manual. 

DataRetrieve works with Atari ST systems with one or 
more single- or double-sided disk drives. Works with 
either monochrome or color monitors. Printer optional. 


DataRetrieve 

The electronic 

ys 

:h( 


Desk Fi le Change Options Input/Output He 1p 

K j I wajq&Wr *At Hf. M H EU T E S T11 M I 
►Search node* Data records : 18 Index : No active Index - ] 



Product Type : Softmr;_ 

Product None T pataTriev 


hndre Classen 
perd-UMe Meukmp 


Hunber of Pages 
ISBN a 
Description 


DataRetrieve 


Suggested Retail Price: $49.95 


DataRetrieve Features: 

• Easily define your files using drop-down menus 

• Design screen mask size to 5000 by 5000 pixels 

• Choose from six font sizes and six text styles 

• Add circles, boxes and lines to screen masks 

• Fast search and sort capabilities 

• Handles records up to 64,000 characters in length 

• Organize files with up to 20 indexes 

• Access up to four files simultaneously 

• Cut, past and copy data to other files 
■ Change file definitions and format 

• Create subsets of files 

• Interfaces with TextPro files 

• Complete built-in reporting capabilities 

• Change setup to support virtually any printer 

• Add header, footer and page number to reports 

• Define printer masks for all reporting needs 

• Send output to screen, printer, disk or modem 

• Includes and supports RAM disk for high-speed 
1040ST operation 

• Capacities: max. 2 billion characters per file 

max. 64,000 records per file 
max. 64,000 characters per record 
max. fields: limited only by record size 
max. 32,000 text characters per field 
max. 20 index fields per file 

• Index precision: 3 to 20 characters 

• Numeric precision: to 15 digits 

• Numeric range ±10'308 ti +10^08 


Atari ST, 520ST, 1040ST, 70S, ST BASIC and ST LOGO arc trademarks or registered trademarks of Atari Corp. 
OEM is a registered trademark of Digital Research Inc. 










Selected Abacus Products for the 


rM 


Forth/MT 

Powerful Multi-tasking Language 
for the Atari ST 

Forth is not only a programming language, but also an 
operating environment—the user can program, assemble 
and edit. Since Forth is fast, compact, flexible and 
efficient., it's particularly well-suited to the solution of 
real time problems. In use for more than fifteen years in 
industrial and scientific applications, Forth dramatically 
reduces program development time compared to program¬ 
ming in assembly language or other higher-level 
languages. 

The powerful multi-tasking Forth/MT package was 
designed to make the fullest use of the STs features for 
Forth programming. 

Forth/MT features include: 

• Over 750 words in the Kemal 

• Complete TOS and LINE-A commands available 

• Over 1500 words (disk accessible) 

• Complete 32-bit implementation based on 
Forth-83 standard 

• Machine language sections added for speed 

• Many utilities: full screen editor, monitor, 
disk monitor and Forth macro assembler 

• Utility descriptions stored on disk-you can change 
them to suit your needs 

• Multitasking capability 

• Machine language sections added for 
high-speed operation 

Forth programmers will love the ease of use of this 
excellent package. Forth/MT the perfect tool for 
unleashing the power of the Forth programming 
language on the Atari ST line of computers. 

Forth/MT Suggested retail price: $49.95 




Farth/MT 



Multi-Tasking 

Full-Featured 


POINTER NEW-MOUSE <CR> (DEFINE BUFFER HEADER ) 
0 W, ( MASK COLOR ) 1 W, (MOUSE COLOR ) <CR> 


BIN 0000000000000000 W, <CR> 
0000000000000000 W, <CR> 
0001111001111000 W, <CR> 
0001111001111000 W, <CR> 
0001001001001000 W, <CR> 
0001001001001000 W, <CR> 
0001001001001000 W, <CR> 
0000001000001000 W, <CR> 
0000000000000000 W, <CR> 
0000101010100000 W, <CR> 
0000011111100000 W, <CR> 
0000001001000000 W, <CR> 
0000000000000000 W, <CR> 
0000000000000000 W, <CR> 
0000000000000000 W, <CR> 
0000000000000000 W, <CR> 
0000000000000000 W, <CR> 
0001111001111000 W, <CR> 
0010000110000100 W, <CR> 
1010000110000101 W, <CR> 
1110110110110111 W, <CR> 
1110110110110111 W, <CR> 
1110110110110111 W, <CR> 
0111110111110110 W, <CR> 
0111111111111110 W, <CR> 
0011010101011100 W, <CR> 
0001100000011000 W, <CR> 
0001110110111000 W, <CR> 
0000111111110000 W, <CR> 
0000001111000000 W, <CR> 
0000001111000000 W, <CR> 
0000000000000000 W, <CR> 
NEW-MOUSE TRANSFORM <CR> { £ 


> ( 1ST MASK LINE ) 

l> ( 2ND MASK LINE ) | 

[> ( 3RD MASK LINE ) j 

i> ( 4TH MASK LINE ) 

t> ( 5TH MASK LINE ) 

t> ( 6TH MASK LINE ) 

t> ( 7TH MASK LINE ) 

t> ( 8TH MASK LINE ) 

l> ( 9TH MASK LINE ) 

t> ( 10TH MASK LINE ) 

t> ( 11TH MASK LINE ) 

t> ( 12TH MASK LINE ) 

l> ( 13TH MASK LINE ) 

\> ( 14TH MASK LINE ) 

l> ( 15TH MASK LINE ) I 

\> ( 16TH MASK LINE ) 

K> ( 1ST MOUSE LINE ) 

*> ( 2ND MOUSE LINE ) 

K> ( 3RD MOUSE LINE ) 

*> ( 4TH MOUSE LINE ) 

*> ( 5JH MOUSE LINE ) 

K> ( 6TH MOUSE LINE ) 

\> ( 7TH MOUSE LINE ) 

*> ( 8TH MOUSE LINE ) 

\> ( 9TH MOUSE LINE ) 

K> ( 10TH MOUSE LINE ) 

*> ( 11TH MOUSE LINE ) 

*> ( 12TH MOUSE LINE ) 

*> ( 13TH MOUSE LINE ) 

*> ( 14TH MOUSE LINE ) 

R> ( 15TH MOUSE LINE ) 

R> ( 16TH MOUSE LINE ) 

( SET NEW MOUSE ) 

( AND DISPLAY ) 


Atari ST, 52QST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks of Atari Corp. 
GEM is a registered trademark of Digital Research Inc. 















































Selected Abacus Products for the ^ 9 c 4ki^lf J “ 


PaintPro 

Design and graphics software for the ST 

PaintPro is a very friendly and very powerful package 
for drawing and design on the Atari ST computers that 
has many features other ST graphic programs don't 
have. Based on GEM™, PaintPro supports up to three 
active windows in all three resolutions—up to 640x400 
or 640x800 (full page) on monochrome monitor, and 
320 x 200 or 320 x 400 on a color monitor. 

PaintPro's complete toolkit of functions includes text, 
fonts, brushes, spraypaint, pattern fills, boxes, circles 
and ellipses, copy, paste and zoom and others. Text can 
be typed in one of four directions—even upside down— 
and in one of six GEM fonts and eight sizes. PaintPro 
can even load pictures from "foreign" formats (ST 
LOGO, DEGAS, Neochrome and Doodle) for 
enhancement using PaintPro's double-sized picture 
format. Hardcopy can be sent to most popular dot¬ 
matrix printers. 

PaintPro Features : 

• Works in all 3 resolutions (mono, low and medium) 

• Four character modes (replace, transparent, inverse 
XOR) 

• Four line thicknesses and user-definable line pattern 
■ Uses all standard ST fill patterns and user definable 

fill patterns 

• Max. three windows (dependng on available memory) 

• Resolution to 640 x400 or 640x800 pixels 
(mono version only) 

• Up to six GDOS type fonts, in 8-, 9-, 10-, 14-, 16-, 
18-, 24- and 36-point sizes 

• Text can be printed in four directions 

• Handles other GDOS compatible fonts, such as those 

in PaintPro Library # 1 

• Blocks can be cut and pasted; mirrored horizontally 
and vertically; marked, saved in LOGO format, and 
recalled in LOGO 

• Accepts ST LOGO, DEGAS, Doodle & Neochrome 
graphics 

• Features help menus, full-screen display, and UNDO 
using the right mouse button 

• Most dot-matrix printers can be easily adapted 

PaintPro works with Atari ST systems with one or 
more single- or double-sided disk drives. Works with 
either monochrome or color ST monitors. Printer 
optional. 

Suggested Retail Price: $49.95 



PaintPro 


Create double¬ 
sized pictures 


PaintPro 


PaintPro 


Multiple 

windows 


fll\HOIISE.PIC 


1 Pattern Color Help 
itf;\PflIHTPtU.S\Pf>T-EPIT.DR| 

OOOO tom*. PahiPto Itaary 1 contatr 


it susten 
urns 
computer 
chintil 


bold 

Italic 

light 

underllntd 


PaintPro 


ondl con ua* tyL0-5 fonts 

Inaludan palturn adllcr 

fltoailfr TpHintTpro, 
^Jleocfirome and pcgag 
l*lctureff._ 


PaintPro 


Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks of Atari Corp. 
GEM is a registered trademark of Digital Research Inc. 







Selected Abacus Products for the 



PaintPro Library #1 

Fonts and Clipart for the Atari ST 

The ST's excellent graphics capability make it a natural 
for computer art and design. To add even more 
flexibility and features to PaintPro we've released 
PaintPro Library #1, a companion graphics package that 
contains a diverse range of fonts and symbols for almost 
every application. It contains five new original fonts for 
the ST: Swiss, Computer, Chantal, Mixed and Thames. 
Paint Pro Library #1 also contains scores of new 
symbols, borders and ornamental lines. As you can see 
from the examples in the next column, this program 
fills a real need for your customers' design requirements. 

PaintPro Library #1 contains five new specially 
designed fonts: 


■ Computer Computer 

■ Chantal 

■Mixed ^XA/IQQ 

■ Thames (Old English) v_J V V IOO 

CUal F Hixsc! SB 

J-Wdl 16 , Mixed IE, fHiXEc' c""! 

(fpljameg 2^ and ^8 


Also included in PaintPro Library #1: 


■ Over 50 drafting symbols 

■ Over 100 electronic symbols 

■ Over 100 clip art symbols 


-ft- -t*p 


bd U 




All fonts are GDOS compatible and may be used with 
"foreign” software that supports the GDOS. PaintPro 
Library #1 also has hundreds of symbols, borders, and 
ornamental lines for use in your graphic designs. These 
libraries are DEGAS® compatible. 

PaintPro Library #1 Suggested retail price: $29.95 



Atari ST, 52QST, 1040ST, TOS, ST BASIC and ST LOOO are trademarks or registered trademarks of Atari Corp. 
OEM is a registered trademark of Digital Research Inc. 











Selected Abacus Products for the 



PCBoard 

Designer 

Interactive CAD Package 
for printed circuit board layout 
on the Atari ST 


PCBoard Designer is an interactive, computer-aided 
design package for creating electronic printed circuit 
boards. It drastically reduces the cost, time and tedium of 
making one or two-sided pc boards. The advanced 
features of PCBoard Designer can improve a designer's 
productivity ten-fold. 

PCBoard Designer is easy to use. Design parameters are 
conveniently entered and modified at the computer. The 
user can position the components interactively by 
moving them on the screen using the mouse. This lets 
the user compare alternative component placement with 
no extra effort. 

As the user position the components on the screen 
using the mouse, PCBoard Designer displays the new 
connections! Automatic routing is fast and precise. 

The most powerful feature of PCBoard Designer is its 
fast automatic routing capability. Traces are 
automatically and precisely drawn on the screen. If the 
user changes the design, the traces can be immediately 
redrawn—this feature alone can save an enormous 
amount of time and money. In addition, the user has 
options of 4S° or 90° angle traces , different trace widths, 
routing from pin to pin, pin to BUS, BUS to BUS, as 
well as two-sided boards. The rubberbanding feature lets 
you see the user-defined components during 
placement—and the user can reposition your 
components at any time during the design process. 

PCBoard Designer prints the completed layout to any 
Epson/compatible dot matrix printer and Hewlett- 
Packard plotters at 2:1. The high-quality printout is 
camera-ready for final photo-etching. PCBoard Designer 
also prints the component layout, and lists every 
component and connection as well. 


PCBoard 


Designer 


Create printed circuit board layouts 



How PCBoard Designer works 

There are basically four steps in creating a working 

pc board: 

• Specify the components: For example, IC4 is an 
integrated circuit that fits in a 14-pin dual-in-line 
socket. You can also define custom component 
types, for example a 99-pin circular IC. 

• Specify the connections: For example, pin 2 of 
integrated circuit IC4 is connected to lead 1 of 
transistor Q7. You can change the connections at 
any time. 

• Position the components: Move the components 
to their desired position on the screen by using 
the Atari STs mouse. You can reposition them at 
any time. PCBoard Designer automatically routes 
the connections when you're done. 


In conjuction with the Atari ST computer, PCBoard Hewlett-Packard plotter. T1 
Designer is the most affordable PC board CAD package for photoetching. You 

available. It boasts features that not available on component layout (for 

systems costing thousands of dollars. component list, and the list i 

_ Atari ST, 52GST, 1040ST, TOS, ST BASIC and ST LOOO are trademarks or registered trademarks of Atari Corp. 

OEM is a registered trademark of Digital Research Inc. 


Output the design: The finished board can be 
printed on any Epson/compatible printer or 
Hewlett-Packard plotter. The printout is suitable 
for photoetching. You can also print the 
component layout (for silkscreening), the 
component list, and t h; lis t of co nnections._ 


















Selected Abacus Products for the 


[Miisiism 


_lnk_ nit ll»lt L Ij Olt IlltlM Hl» • 11_• t tJ 111_ 




I t ill flit I nnt_Li| 0 »t I 


, J Olipllll lottOM 
I / Ont'ildtl 
l Minhittn 
- V Report 


_ L i^C|i»r FC loir i 'J 

■—i h~ = ¥& 

1 

"I was thoroughly impressed... a powerful, multi- 
featured design tool that can be easily learned and 

used." 

—Bill Marquardt 
Input magazine 

"What makes this program especially easy to use 
is that the components are drawn to scale on the 
screen. This comes in handy when it's time for 
the user to position the components. 

"The author invested a lot of blood, sweat and 
tears writing this portion of the program. PCBoard 
Designer has a wide selection of options here that 
allow for flexible design. Either all of the 
connections or an individual connection can be 
routed at the click of the mouse button. 

"One thing is clear, though: author Florian 
Sachse has produced a first-class software packa ge. 
This program will undoubtedly be a godsend to the 
engineer and electronic hobbyist alike. 

—DATA WELT Magazine 
APRIL 1986 

Abacus Software, Inc. 

5370 52nd St. S.B. 

Grand Rapids, MI 49508 


(616) 698-0330 


PCBoard Designer (continued) 

PCBoard Designer Features: 

• PC boards may be one-sided or two-sided 

• Components are drawn to scale on the screen 

• Custom components may be used 

• Component positioning is flexible and interactive 

• Components may be roatated in 90° increments 

• Traces are drawn using sophisticated and fast 
automatic routing techniques—the user has the ability 
to make 45 s and 90° angle traces, variable trace 
widths, pin to pin, pin to bus and bus to bus routing 

• "Blockades" may be inserted onto the board to handle 
special cases 

• Printout is high quality and suitable for photo¬ 
reproduction 

• Features are clearly displayed and are selectable from 
the drop-down menus 


Hardware Requirements: 

Computer: Atari 520ST or 1040ST computer and 
monochrome monitor with one or more single-sided, 
double-sided, or hard disk drives. 

Printers/Plotters: PCBoard Designer prints your 
completed layout to any Epson or Epson-compatible dot 
matrix printer at 2:1. Epson FX-80, FX-100, Toshiba, 
NEC P6 and P7 or compatible printersrequired for photo¬ 
ready traces. Also works on Hewlett/Packard plotters. 

Package: Includes 100 page manual in 3-ring slipcase 
binder and program diskette. 

Free phone support to registered users. 

PCBoard Designer can dramatically improve design 
productivity by eliminating many redundant steps and 
time-consuming alterations. With all of its advanced 
time-saving capabilities, PCBoard Designer pays for 
itself after the first successfully designed board. 


PCBoard Designer 

Suggested Retail Price: 

$195.00 


Atari ST, 520ST, 1040ST, TOS, ST BASIC and ST LOGO arc trademarks or registered trademarks of Atari Corp. 
GEM is a registered trademark of Digital Research Inc. 










Selected Abacus Products for the 


AIMfASf 


PowerLedger ST 

(formerly PowerPlan ST) 

Spreadsheet/Graphics package 
for the Atari ST 

"A superior spreadsheet program for weekend 
bookeeping to the heavyweight job costing appli¬ 
cations, (Powerledger ST) is a definite winner." 

—Judi Lambert 
ST World 

Ever since VisiCalc and Lotus 1-2-3 stormed the 
personal computer market, the computer has become an 
important planning tool. PowerLedger ST brings the 
power of electronic spreadsheets to the Atari ST line of 
computers—it lets the user quickly perform hundreds of 
calculations and "what-if' analyses for business 
applications, and crunch raw data into meaningful, 
comprehensible information, to keep track of budgets, 
expenses and statistics. 

PowerLedger ST is a powerful analysis package that 
features a large spreadsheet (65,536 X 65,536 
cells—over 4 billion data items). It also contains a 
built-in calculator, online notepad, and integrated 
graphics. 

PowerLedger ST is also very easy to learn, since it uses 
the familiar GEM features built into the ST. And 
PowerLedger ST can use multiple windows—up to 
seven. Data from the spreadsheet can be graphically 
summarized in in pie charts, bar graphs and line charts, 
and displayed simultaneously with the spreadsheet. For 
example, one window can display part of the 
spreadsheet; a second window a different part; and a third 
window, a pie or bar chart of the data. 

PowerLedger ST works hand-in-hand with our 
DataTrieve data management package and our TextPro 
wordprocessing package. 

PowerLedger ST's extraordinary combination of data and 
graphic power, ease of use and low price makes it a 
perfect tool for every ST owner's financial planning 
needs. 

PowerLedger ST works with Atari ST systems with one 
or more single- or double-sided disk drives. Works with 
either monochrome or color ST monitors. Works with 
most popular dot-matrix printers (optional). 



Powerledger ST Features: 

• Familiar drop-down menus make PowerPlan easy to 
learn and use 

• Large capacity spreadsheet serves all the user's 
analysis needs 

• Convenient built-in notepad documents your 
important memos 

• Flexible online calculator gives you access to quick 
computations 

• Powerful options such as cut, copy and paste 
operations speeds the user'swork 

• Integrated graphics summarize hundreds of data items 

• Draws pie, bar, 3D bar, line and area charts 
automatically (7 chart types) 

• Multiple windows emphasize the user's analyses 

• Accepts information from DataTrieve, our database 
management software 

• Passes data to TextPro wordprocessing package 

• Capacities: maximum of 65,535 rows 

maximum of 65,535 columns 
variable column width 
numeric precision of 14 digits 
maximum value 1.797693 x 1(P^ 
minimum value 2.2 x 10'308 
37 built-in functions 

PowerLedger ST Suggested Retail Price: $79.95 


Atari ST, 52QST, 1040ST, TOS, ST BASIC anJ ST LOGO are trademarks or registered trademarks of Atari Corp. 
OEM is a registered trademark of Digital Research Inc. 






















Selected Abacus Products for the 


TextPro 

Wordprocessing package 
for the Atari ST 

"TextPro seems to be well thought out, easy, flexible 
anf fast. The program makes excellent use of the GEM 
interface and provides lots of small enhancements to 
make your work go more easily... if you have an ST 
and haven’t moved up to a GEM word processor, pick 
up this one and become a text pro." 

—John Kintz 
ANTIC 

"TextPro is the best wordprocessor available for the ST" 

—Randy McSorley 
Pacus Report 

TextPro is a first-class word processor for the Atari ST 
that boasts dozens of features for the writer. It was 
designed by three writers to incorporate features that 
they wanted in a wordprocessor—the result is a superior 
package that suits the needs of all ST owners. 

TextPro combines its " extra" features with easy 
operation, flexibility, and speed—but at a very 
reasonable price. The two-fingered typist will find 
TextPro to be a friendly, user-oriented program, with all 
the capabilities needed for fine writing and good-looking 
printouts. Textpro offers full-screen editing with mouse 
or keyboard shortcuts, as well as high-speed input, 
scrolling and editing. TextPro includes a number of easy 
to use formatting commands, fast and practical cursor 
positioning and multiple text styles. 

Two of TextPro's advanced features are automatic table 
of contents generation and index generation 
—capabilities usually found only on wordprocessing 
packages costing hundreds of dollars. TextPro can also 
print text horizontally (normal typewriter mode) or 
vertically (sideways). For that professional newsletter 
look, TextPro can print the text in columns—up to six 
columns per page in sideways mode. 

The user can write form letters using the convenient 
Mail Merge option. TextPro also supports GEM- 
oriented fonts and type styles—text can be bold, 
underlined, italic , superscript, omgiinieidl, etc., and in a 
number of point sizes. TextPro even has advanced 
features for the programmer for development with its 
Non-document and C-sourcecode modes. 

TextPro Suggested Retail Price: $49.95 




TextPro ST Features: 


• Full screen editing with either mouse or keyboard 

• Automatic index generation 

• Automatic table of contents generation 

• Up to 30 user-defined function keys, max. 160 
characters per key 

• Lines up to 180 characters using horizontal scrolling 

• Automatic hyphenation 

• Automatic wordwrap 

• Variable number of tab stops 

• Multiple-column output (maximum 5 columns) 

• Sideways printing on Epson FX and compatibles 

• Performs mail merge and document chaining 

• Flexible and adaptable printer driver 

• Supports RS-232 file transfer (computer-to-computer 
transfer possible) 

• Detailed 65+ page manual 

TextPro works with Atari ST systems with one or more 
single- or double-sided disk drives. Works with either 
monochrome or color ST monitors. 

TexPro allows for flexible printer configurations with 
most popular dot-matrix printers. 


Auri ST, 52QST, 1040ST, TOS, ST BASIC and ST LOGO are trademarks or registered trademarks of Atari Corp. 
GEM is a registered trademark of Digital Research Inc. 























Selected Abacus Products for the 


I'M 


BeckerText ST 

The High-Powered Word 
Processing Package for the ST 

A word processing package for serious Atari ST owners. 
Because BeckerText is more than a word processor. 

It has all the features of our TextPro, and more: 
WYSIWYG formatting and printing, graphic merge 
capabilities, automatic hyphenation and indexing of your 
documents. 

But BeckerText also does a few things that you might 
not expect...like calculate numbers within text , with 
templates for calculations in up to five columns. (It's just 
like having a spreadsheet program built into your word 
processor!). BeckerText prints up to five columns of 
text a page for professional-looking newsletters, 
presentations, reports, etc. It even has two expandable 
spelling checkers for 100% spelling accuracy. 

BeckerText is also.a perfect choice for C language 
programmers as an extremely flexible C editor. Whether 
you’re deleting, adding or duplicating a block of C source 
code, BeckerText does it all, automatically. The online 
dictionary can double as a C syntax checker—catch those 
syntax errors immediately. 

BeckerText gives you the power and flexibility to 
produce the professional-quality documents that you 
demand. It adapts to,most popular dot-matrix and letter- 
quality printers. Includes a comprehensive tutorial, manual 
and glossary. 

When you need more from your word processor than just 
word processing, you need BeckerText. Discover the 
power of BeckerText. 

Suggested retail price: $99.95 



Abacus 53 


BeckerText Features: 

• Select options from dropdown menus or shortcut keys 

• Fast WYSIWYG formatting 

• Bold, italic, underline, superscript and subscript 
characters 

• Automatic wordwrap and page numbering 

• Sophisticated tab and indent options, with centering & 
margin justification 

• Move, Copy, Delete, Search & Replace options 

• Automatic hyphenation & automatic indexing 

• Write up to 999 characters per line with horizontal 
scrolling feature 

• Online dictionary checks spelling as you're writing 

• Spelling checker interactively proofs text 

• Calculates numbers within text—use templates to 
calculate in columns 

• Customize up to 30 function keys to store often-used 
text and macro commands 

• Merge graphics into documents 

• Includes BTSnap program for converting text blocks 
to graphics 

• C-source mode for quick and easy C language program 
editing 

• Multiple-column printing—up to five columns on a 
single page 

• Adapts to virtually any dot-matrix or letter-quality 
printer 

• Load & save files through the RS-232 port 

• Comprehensive tutorial and manual 

• Not copy protected 


AUii ST, 520ST, 1040ST, TOS, ST BASIC and ST IjOOO are trademarks or registered trademarks of Atari Corp. 
OEM is a registered trademark of Digital Research Inc. 




We have the software 
you’ve been looking for! 


DataRetrieve 

The electronic 
filing system 
for the ST 






k. 


ST DataTrieve 

Data management was never this 
easy. Online help screens; lightning- 
fast operation; tailorable display; user- 
definable edit masks; up to 64,000 
records. Supports multiple files. In¬ 
cludes RAM-disk programs. Complete 
search, sort and file subsetting. Inter¬ 
faces to TextPro. Easy yet powerful 
printer control. Includes five common 
database setups. $49.95 


Word processor for the ST 


ST TextPro 

Wordprocessor with professional 
features and easy-to-usel Full-screen 
editing with mouse or keyboard 
shortcuts. High speed input, scrolling 
and editing; sideways printing; 
multi-column output; flexible printer 
installation; automatic index and table 
of contents; up to 180 chars/line; 30 
definable function keys; metafile 
output; much more. $49.95 


ST PalntPro 

Friendly, but powerful design and paint¬ 
ing program. A must for everyone's 
artistic and graphics needs. Up to three 
windows. Cut & paste between win¬ 
dows. 36 user-defined fill patterns; 
definable line patterns; works in hi- 
med- & lo-res; accepts GDOS fonts. 
Double-sized picture format. $49.95 

PainIPro Library #1 5 fonts, 300+ electronic, 
architectual, borders & dip art designs. $19.95 



AssemPro 

The complete 68000 
assembler development 
package for the ST 


ST Forth/MT 

Powerful, multi-tasking Forth for the ST. 
A complete, 32-bit implementation 
based on Forth-83 standard. Develop¬ 
ment aids: full screen editor, monitor, 
macro assembler. 1500+ word library. 
TOS/LINEA commands. Floating point 
and complex arithmetic. $49.95 


PowerPlan ST 

Full-powered Spreadsheet 

37 math functions -14 digit precision _ 

Large size - over 4.2 billion cells 
Multiple windows - up to 7 
Graphics - 7 types of grapl 




ST AssemPro 

Professional developer's package 
includes editor, two-pass interactive 
assembler with error locator, online help 
including instruction address mode and 
GEM parameter information, 
monitor-debugger, disassembler and 
68020 simulator, more. $59.95 


PowerPlan ST 

Powerful analysis package. Large 
spreadsheet (65536 X 65536 cells), 
built-in calculator, notepad, and inte¬ 
grated graphics. 37 math functions, 14 
digit-precision. Seven windows to show 
one of seven types of charts or another 
section of your spreadsheet. $79.95 

ST and 1040ST are trademarks of Atari Corp. 


Other software and books also available. Call or write 
for your free catalog or the name of your nearest 
dealer. Or order directly using your VISA, MC or Amex 
card. Add $4.00 per order for shipping and handling. 
Foreign orders add $10.00 per item. 30-day money 
back guarantee on software. Dealers inquires 
welcome-over 1500 dealers nationwide. 




Abacus Software • 5370 52nd Street SE 
Grand Rapids, Ml 49508 • Phone (616) 698-0330 





































INTERNALS GEM Programmer’s Ref. TRICKS & TIPS GRAPHICS & SOUND BASIC Training Guide 

Essential guide to learning the For serious programmers in Fantastic collection of pro- Detailed guide to understand- Indispensible handbook for 

inside information of the ST. need of detailed information grams and info for the ST. ing graphics & sound on the beginning BASIC program- 

Detailed descriptions of sound on GEM. Written with an Complete programs include: ST. 2D & 3D function plotters, mers. Learn fundamantals of 

& graphics chips, internal easy-to-understand format. All super-fast RAM disk; time- Moir6 patterns, various reso- programming. Flowcharting, 

hardware, various ports. GEM. GEM examples are written in saving printer spooler; color lutions and graphic memory. numbering system, logical 

Commented BIOS listing. An C and assembly. Required print hardcopy; plotter output fractals, waveform generation. operators, program structures, 

indispensible reference for reading for the serious pro- hardcopy. Money saving tricks Examples written in C. LOGO, bits & bytes, disk use, chapter 

your library. 450pp. $19.95 grammer. 450pp. $19.95 and tips. 200 pp. $19.95 BASIC and Modula2. $19.95 quizzes. 200pp. $16.95 



PRESENTING THE ST MACHINE LANGUAGE LOGO PEEKS & POKES BEGINNER’S GUIDE BASIC TO C 


Gives you an in-depth Program in the fastest Take control of your Enhance your programs Finally a book for those If you are already familiar 

look at this sensational language for your Atari ATARI ST by learning with the examples found new to the ST wanting to with BASIC, learning C 

new computer. Discusses ST. Learn the 68000 LOGO-the easy-to-use, within this book. Explores understanding ST basics, will be all that much 

the architecture of the assembly language, its yet powerful language, using the different lang- Thoroughly understand easier. Shows the trans- 

ST, working with GEM, numbering system, use Topics covered include uages BASIC, C, LOGO your ST and its many ition from a BASIC 

the mouse, operating of registers, the structure structured programming, and machine language, devices. Learn the funda- program, translated step 

system, ail the various & important details of the graphic movement, file using various interfaces, mentals of BASIC, LOGO by step, to the final C 

interlaces, the 68000 instruction set, and use of handling and more. An memory usage, reading and more. Complete with program. For all users 

chip and its instructions, the internal system excellent book for kids as and saving from and to index, glossary and illus- interested in taking the 

LOGO. $16.95 routines. 280pp $19.95 well as adults. $19.95 disk, more. $16.95 trations. +200pp $16.95 nextstep. $19.95 


Abacus 



The ATARI logo and ATARI ST are Xademarks of Atari Corp. 

Software 


5370 52nd Street SE Grand Rapids, Ml 49508 Phone (616) 698-0330 

Optional diskettes are available for all book titles at $14.95 

Call now for the name of your nearest dealer. Or order directly from ABACUS with your MasterCard, VISA, or Amex card. Add 
$4.00 per order for postage and handling. Foreign add $10.00 per book. Other software and books coming soon. Call or 
write for your free catalog. Dealer inquiries welcome-over 1400 dealers nationwide. 












/WAS? 

REFERENCE UBRARY 



Essential guide to learning 
the inside information on the 
ATARI ST. Written for the 
user who wants thorough 
and complete descriptions of 
the inner workings of the ST. 
Detailed descriptions of the 
sound and graphics chips, 
the internal hardware, the 
Centronics and RS-232 
ports, GEM, important system 
addresses and plenty more. 
Also included is a complete 
documented BIOS assembly 
listing. This indispensible 
reference is a required 
addition to your ATARI ST 
library. 450 pages. $19.95 



For the serious programmer 
in need of detailed inform¬ 
ation on the GEM operating 
system. Written especially for 
the Atari ST with an easy-to- 
understand format that even 
beginners will be able to 
follow. All GEM routines and 
examples are written in C 
and 68000 assembly 
language. Covers working 
with the mouse, icons, Virtual 
Device Interface (V D I), 
Application Environment 
Services (AES) and the 
Graphics Device Operating 
System. Required reading for 
the serious programmer 
intrested in understanding 
the ST. 450 pages. $19.95 



MACHINE LANGUAGE TRICKS & TIPS GRAPHICS & SOUND 

Program in the fastest Treasure trove of fascin- A comprehensive hand- 

language for your Atari ating tips and tricks book showing you how to 

ST. Learn the 68000 allows you to make full create fascinating graph- 

assembly language, its use of your ATARI ST. ics and suprising music 

numbering system, use Fantastic graphics, refin- and sound from the 

of registers, the structure ing programs in BASIC, ATARI ST. See and hear 

& important details of the assembler, and C. what sights and sounds 

instruction set, and use of Includes program listings that you're capable of 

the internal system for RAM disk, printer producing from your 

routines. 280pp $1955 spooler and more. $19.95 ATARI ST. $19.95 


LOGO PEEKS & POKES PRESENTING THE ST 

Take control of your Enhance your programs Gives you an in-depth 

ATARI ST by-learning with the examples found look at this sensational 

LOGO-the easy-to-use, within this book. Explores neyir computer. Discusses 

yet powerful language, using the different lang- the architecture of the 

Topics covered include uages BASIC, C, LOGO ST, working with GEM, 

structured programming, and machine language, the mouse, operating 

graphic movement, file using various interfaces, system, all the various 

handling and more. An memory usage, reading interfaces, the 68000 

excellent book for kids as and saving from and to chip and its instructions, 

well as adults. $19.95 disk, more. $16.95 LOGO. $16.95 


Abacus 


111 


Software 


5370 52nd Street SE Grand Rapids, Ml 49508 Phone (616) 698-0330 


Optional diskettes are available for all book titles at $14.95 

Call now for the name of your nearest dealer. Or order directly from ABACUS with your MasterCard, VISA, or 
Amex card. Add $4.00 per order for postage and handling. Foreign add $10.00 per book. Other software and 
books coming soon. Call or write for free catalog. Dealer inquiries welcome-over 1200 dealers nationwide. 











We have the software 
you’ve been looking for! 


PowerLedger 

Full-powered Spreadsheet 

37 math functions -14 digit precision 
Large size - over 4.2 billion cells ^ 
Multiple windows - up to 7 
Graphics - 7 types of graphs_ ( ' 


A superior spreadsheet program 
for weekend bookkeeping to the 
heavyweight job costing app¬ 
lications...a definite winner! 

Judi Lambert, ST World 


Formerly 
PowerPlan ST 




PaintPro 


cells) spreadsheet package that also features 
a built-in calculator, online notepad and 
integrated graphics. Displays your data in 
numerical or graphical format instantly in up 
to seven different chart types (pie, bar, 3D 
bar, line, etc.). 14 digit precision with 37 math 
functions and more. $79.95 


Multiple 

__o c 2 > <2>windows 


Express yourself with PaintPro, the GEM- 
based, full-page graphics design package. 
Multiple windows. Cut & paste between 
windows. Free-form sketching; lines, circles, 
boxes, text, fill, zoom, undo, rotate, invert, 
help. Edit fill and line patterns. $49.95 

PaintPro Library #1-hundreds of clip art 
pictures, 5 GDOS fonts. Fills 3 disks. $29.95 


DataTrleve is...the most 
versatile, and yet simple, data 
base available for the ST on 
the market to dale. 

The Atari Journal, Nov. ‘86 


Data management was never this easy. Help 
screens; lightning-fast operation; tailorable 
display; user-definable edit masks; up to 
64,000 records. Supports multiple files. 
Includes RAM-disk programs. Complete 
search, sort and file subsetting. Interfaces to 
TextPro. Easy printer control. Includes five 
common database setups. $49.95 



One good book., 

1 "deserves another... 


INTERNALS 


and another... and another... 


and another... 



ST Disk Drives - Inside and Out 

Includes chapters on files, file structures 
and data management. Thoroughly 
discusses floppy disks, hard disks and 
RAM disks from a programming and a 
technical perspective. Several full-length 
utilities and tools to further explore the 
ST disk drives. 450pp $24.95 


ST INTERNALS 

Essential and valuable information for 
the professional programmer and ST 
novice. Detailed descriptions of the 
sound and graphics chips, internal 
hardware, I/O ports, using GEM, 
system variables, interrupt instruct¬ 
ions, error codes. Commented BIOS 
listing. An indispensible reference for 
your ST library. 450pp >10.95 


3D Graphics Programming 

FANTASTICI Rotate about 
any axis, zoom in or out, and 
shade 3D objects. Programs 
written in machine language 
(commented) for high speed. 
Learn the theory behind 3D 
graphics; shading, hidden 
line removal. With 3D pattern 
maker & animator. $24.95 


Optional diskettes are available for $14.95 each. 

m | _ you can count on 


5370 52nd Street SE 
Grand Rapids, Ml 49508 
Phone (616) 698-0330 


ST TRICKS & TIPS GEM Programmer's Ref. 

Fantastic collection of pro- For serious programmers 
grams and info for the ST. needing detailed information 
Complete programs include: on GEM. Presented in an 
super-fast RAM disk; time- easy-to-understand format, 
saving printer spooler; color All examples in C and 
print hardcopy; plotter output assembly language. Covers 
hardcopy; creating access- VDI and AES functions. No 
ories. Money saving tricks serious programmer should 
and tips. 260pp $19.95 be without. 410pp $19.95 
Atari and Atari ST are trademarks of Atari Corp. 

GEM is a trademark of Digital Research Inc. 


Other software and books also available. Call or 
write for your free catalog or the name of your 
nearest dealer. Or you can order directly using your 
Visa, MC or Amex. Add $4.00 per order for shipping 
and handling. Foreign orders add $12.00 per item. 
30-day money back guarantee on software. Dealers 
inquires welcome—over 2000 dealers nationwide. 


















































































3D GRAPHICS 


GEM Programmers R«f. MACHINE LANGUAGE ST TRICKS A TIPS 


FANTASTIC! Rotate, zoom, and shade EM.na.i 9 uM. to a» insid. 

3D objects. All programs written in o"l?XV°!L°ripiio™ It 

machine language for high speed. Learn sound and graphics chips, 

the mathematics behind 3D graphics. internal hardware, i/o ports. 

Hidden line removal, shading. With 3D “T 

pattern maker and animator. $24.95 slb ie reference for your st 

library, 450pp $19 95 


For serious programmers Program in the fastest lang- Fantastic collection of pro- 
needing detailed information uage for your ATARI ST grams and info for the ST 
on GEM. Presented in an Learn 60000 assembly lang- Complete programs include 
easy-to-understand format uage. its numbering system, super-fast RAM disk; time- 
All examples are in C and use erf registers, structure & saving printer spooler; color 
assembly language Covers important details of instruc- print hardcopy; plotter output 
VDI and AES functions. No tion set. and use of internal hardcopy; creating access- 
serious programer should be system routines Geared for ories Money saving tricks 
without 41 Opp $19 95 the ST. 280pp $19 95 and tips 260pp $1995 



ST GRAPHICS & SOUND 
Detailed guide to graphics 
and sound on the ST. 2D 4 
3D function plotters, Moir6 
patterns, graphic memory 
and various resolutions, 
fractals, recursion, waveform 
generation. Examples written 
in C. LOGO, BASIC and 
Module2 25Opp $19 95 


ST LOGO GUIDE 
Take control of your ST by 
learning ST LOGO—the easy 
to use. powerful language. 
Topics indude: file handling. 
recursion-Hilbert 4 Sierpinski 
curves. 2D and 3D function 
plots, data structure, error 
handling. Helpful guide for 
ST LOGO users $19 95 


ST PEEKS & POKES 
Enhance your programs with 
the examples found within 
this book. Explores using 
different languages BASIC. 
C, LOGO and machine 
language, using various 
interfaces, memory usage, 
reading and saving from and 
to disk, more 280pp $16 95 


BASIC Training Guide 
Thorough guide for learning 
ST BASIC programming. 
Detailed programming funda¬ 
mentals. commands descrip¬ 
tions, ST graphics 4 sound, 
using GEM in BASIC, file 
management, disk operation. 
Tutorial problems give hands 
on experience 300pp $16 95 


BASIC to C 

Move up from BASIC to C. If 
you're already a BASIC 
programmer, you can learn C 
all that much faster. Parallel 
examples demostrate the 
programming techniques and 
constructs in both languages. 
Variables, pointers, arrays, 
data structure. 250pp $19.95 


ST Beginner's Guide 
Written for the firsthand ST 
user. Get a basic understand¬ 
ing of your ST. Explore 
LOGO and BASIC from the 
ground up. Simple explan¬ 
ations of the hardware and 
internal workings of the ST. 
Illustrations, diagrams Gloss¬ 
ary. Index 20Opp $16 95 


The ATARI logo and ATARi ST are tademarks of Atari Corp. 


Optional diskettes are available for $14.95 each. 
Call now for the name of the dealer nearest you. 
Or order directly using your MC, Visa or Amex 
card. Add $4.00 per order for shipping. Foreign 
orders add $10.00 per item. Call (616) 698-0330 
or write for your free catalog. Dealers inquires 
welcome- over 1400 dealers nationwide. 


mmtmi 


5370 52nd Street SE 
Grand Rapids, Ml 49508 
Phone (616) 698-0330 








AA Rated Software 


Atari and Abacus 



PaintPro 


PaintPro 


PaintPro 


Multiple 

windows 


A GEM™ among ST drawing programs. Very 
friendly, but very powerful design and painting 
program. A must for everyone's artistic or 
graphics needs. Use up to three windows. 
Cut & paste between windows. Free-form 
sketching; lines, circles, ellipses, boxes, text, 
fill, copy, move, zoom, spray, paint, undo, 
help. Double-sized picture format. $49.95 



DataRetrleve 

——-^The quick and effecient 
v way of retrieving 

^N-^-^s^S'gLdata on the ST 


Data management was never this easy. Help 
screens; lightning-fast operation; tailorable 
display; user-definable edit masks; up to 
64,000 records. Supports multiple files. 
Includes RAM-disk programs. Complete 


search, sort and file subsetting. Interfaces to 


TextPro. Easy printer control. Includes five 


common database setups. $49.95 



Wordprocessor with professional features 
and easy-to-usel Full-screen editing with 
mouse or keyboard shortcuts. High speed 
Input, scrolling and editing; sideways printing; 
multi-column output; flexible printer install¬ 
ation; automatic index and table of contents; 
up to 180 chars/line; 30 definable function 
keys; metafile output; much more. $49.95 





,//<///////* 


One good book. 

.. __■ i_ 


' deserves another 

and another, 


and another. 


and another. 


INTERNAL: 


ST INTERNALS 

3D GRAPHICS PROGRAMMING Essential and valuable information for 
FANTASTIC! Rotate about any axis, the professional programmer and ST 
zoom in or out, and shade 3D objects. All novice. Detailed descriptions of the 
programs written in machine language sound and Sophies chips, internal 

(and commented) for high speed. Learn ^“mvariLSesTmirmpHns?™^ 
the mathematics behind 3D graphics, j 0 ns, error codes, commented bios 
Hidden line removal, shading. With 3D listing. An indispensible reference for 
pattern maker and animator. $24.95 your st library. 450pp $1945 

Optional diskettes are available for $14.95 each. 


ST PEEKS & POKES 

Enhance your programs with 
the examples found within 
this book. Explores using 
different languages BASIC, 
C, LOGO and machine 
language, using various 
interfaces, memory usage, 
reading and saving from and 
to disk. 280pp 91645 


ST TRICKS & TIPS GEM Programmer's Ref. 

Fantastic collection of pro- For serious programmers 
grams and info for the ST. needing detailed information 
Complete programs include: on GEM. Presented in an 
super-fast RAM disk; time- easy-to-understand format, 
saving printer spooler; color All examples in C and 
print hardcopy; plotter output assembly language. Covers 
hardcopy; creating access- VDI and AES functions. No 
ories. Money saving tricks serious programer should be 
and tips. 260pp $1945 without. 410pp $19.95 
Atari and Atari ST are trademarks of Atari Corp. 

GEM is a trademark of Digital Research Inc. 



5370 52nd Street SE 
Grand Rapids, Ml 49508 
Phone (616) 698-0330 


Other software and books also available. Call or 
write for your free catalog or the name of your 
nearest dealer. Or order directly using your credit 
card. Add $4.00 per order for shipping. Foreign 
orders add $10.00 per item. 30-day money back 
guarantee on software. Dealers inquires welcome- 
over 1500 dealers nationwide. 




















































Send your completed order blank to: 


How to Order 


Abacus 5370 52nd Street SE Grand Rapids, Ml 49508 


All of our ST products—applications and language software, and our 
acclaimed 14 volume Atari ST Reference Library —are available at 
more than 2000 dealers in the U.S. and Canada. To find out the 
location of the Abacus dealer nearest to you, call: 


(616) 698-0330 

8:30 am-8:00 pm Eastern Standard Time 


Or order from Abacus directly by phone with your credit card. We 
accept Mastercard, Visa and American Express. 

Every one of our software packages is backed by the Abacus 30-Day 
Guarantee-if for any reason you're not satisified by the software 
purchased directly from us, simply return the prooduct for a full refund 
of the purchase price. 




Order Blank 


Ejjifl 


U 

3 

O 


Name: 




Address: 

City_ 


State 


_Zip_ 


Country 


Phone: 


/ 


co 
CO xf 


Qtv 


<D CD : 

^ a> ■ 


■C 

CD 

CL 

CL 


SCO'S 


C/5 


od a 

CO c 03 
CVJ CC 


o o c 
I s ** CO 

jQ ro 

< So 


4) 

.o.ti 

S3 WO 

N 

u '3 

£ y 


"2 « 
u t- 


o 


Name of product 


Price 


Mich, residents add 4% sales tax 


Shipping/Handling charge 

(Foreign Orders $12 per Item) 

Check/Money order TOTAL enclosed 


I 


$4.00 



Credit Card# 



LL 


Expiradon date Cardholder Signature 


I 

J 


For extra-fast 24-hour shipment service, 
order by phone with your credit card 




























Here's a book with in-depth coverage of a neglected ST topic. Learn the 
concepts and techniques for using the floppy, hard and RAM disks. Never 
before has anyone explained in such detail the file structures, software, 
firmware and hardware that supports the ST. 

ST Disk Drives: Inside and Out also includes an extensive description 
and listing for a full-function disk monitor that will make your investigations 
easier and more complete. The monitor lets you look at TRACKS, 
SECTORS, CLUSTERS, GAPS, FATS and more. 

Some of the topics covered are: 

• Files - organization, structure and use from BASIC, Pascal, C and 
68000 machine language. 

• BIOS - Basic Input and Output System 

• DMA - Direct Memory Access 

• Hard and floppy disk controllers 

• Flowcharts for data transfer and controller operation 

About the authors: 

Uwe Braun is a software developer, 68000 specialist and the author of the 
bestseller Atari ST 3D Graphics. Stephan Dittrich is a computer scientist, 
hard disk specialist and the author of the bestseller Atari ST Peeks & Pokes. 
Axel Schramm is a telecommunications student and a floppy disk specialist. 


ISBN □- c Ub43 c i-a4-4 


The ATARI logo and ATARI ST are trademarks of Atari Corp. 



ilUliWU 


HI 


A Data Becker Book 















ATARI 

ST 





(/) 

S-o 

3 5 ? 

3 3. 0) 
5 o c 
3 3-3